Go Design Patterns : Factory
Tags: beginners, programming, productivity, go
Published: 2022-05-20 23:32:07

![Factory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qgl9kvof5t1ucjc6ewzv.png) 

It is a creational pattern that allows us to create a "factory" of objects from a base class and to implement polymorphic behaviors that allow us to modify the behavior of the inherited classes.

It is usually used to reuse the creation logic that shares a series of objects.

Go is not strictly an object-oriented language, but we can implement OOP logic through interfaces and the concept of composition over inheritance.

**Example**
We have a series of products (objects) that behave in a similar way. We can either make a separate class for each one or put all this logic in a base class to create inherited classes for each product.

- First, we need to define an interface that describes the behaviors of our products "made" by our "factory". 
```go
type IProduct interface {
	setStock(stock int)
	getStock() int
	setName(name string)
	getName() string
}
```

- Define how our product look, then implement the IProduct methods in order to comply with the interface. This is similar to define an abstract class. 
```go
type Computer struct {
	name  string
	stock int
}

func (c *Computer) setStock(stock int) {
	c.stock = stock
}

func (c *Computer) getStock() int {
	return c.stock
}

func (c *Computer) setName(name string) {
	c.name = name
}

func (c *Computer) getName() string {
	return c.name
}
```

- Create our product classes that are inherited from the Computer class. Here the concept of composition over inheritance is applied.

```go
type Laptop struct {
	Computer
}

func newLaptop() IProduct {
	return &Laptop{
		Computer: Computer{
			name:  "Laptop Computer",
			stock: 0,
		},
	}
}

type Desktop struct {
	Computer
}

func newDesktop() IProduct {
	return &Desktop{
		Computer: Computer{
			name:  "Desktop Computer",
			stock: 0,
		},
	}
}

```

- Finally, we need to "create" our factory method, this method will return a instance of the object specified.

```go
func GetComputerFactory(computerType string) (IProduct, error) {
	if computerType == "laptop" {
		return newLaptop(), nil
	} else if computerType == "desktop" {
		return newDesktop(), nil
	} else {
		return nil, fmt.Errorf("invalid computer type")
	}
}
```

## Running our code

```go
func PrintNameAndStock(p IProduct) {
	fmt.Printf("Product name: %s, with stock %d\n", p.getName(), p.getStock())
}

func main() {
	laptop, _ := GetComputerFactory("laptop")
	desktop, _ := GetComputerFactory("desktop")
	
	laptop.setStock(10)
	PrintNameAndStock(laptop)
	desktop.setStock(20)
	PrintNameAndStock(desktop)

}
```
Output

```
Product name: Laptop Computer, with stock 10
Product name: Desktop Computer, with stock 20
```

### Full Example

```go
package main

import "fmt"

type IProduct interface {
	setStock(stock int)
	getStock() int
	setName(name string)
	getName() string
}

type Computer struct {
	name  string
	stock int
}

func (c *Computer) setStock(stock int) {
	c.stock = stock
}

func (c *Computer) getStock() int {
	return c.stock
}

func (c *Computer) setName(name string) {
	c.name = name
}

func (c *Computer) getName() string {
	return c.name
}

type Laptop struct {
	Computer
}

func newLaptop() IProduct {
	return &Laptop{
		Computer: Computer{
			name:  "Laptop Computer",
			stock: 0,
		},
	}
}

type Desktop struct {
	Computer
}

func newDesktop() IProduct {
	return &Desktop{
		Computer: Computer{
			name:  "Desktop Computer",
			stock: 0,
		},
	}
}

func GetComputerFactory(computerType string) (IProduct, error) {
	if computerType == "laptop" {
		return newLaptop(), nil
	} else if computerType == "desktop" {
		return newDesktop(), nil
	} else {
		return nil, fmt.Errorf("invalid computer type")
	}
}

func PrintNameAndStock(p IProduct) {
	fmt.Printf("Product name: %s, with stock %d\n", p.getName(), p.getStock())
}

func main() {
	laptop, _ := GetComputerFactory("laptop")
	desktop, _ := GetComputerFactory("desktop")

	laptop.setStock(10)
	PrintNameAndStock(laptop)
	desktop.setStock(20)
	PrintNameAndStock(desktop)
}

```


I hope I have helped you 😊😊