Creational pattern - Factory
Use cases:
- when you don’t know what exact types and dependencies your code should support
- when you want to extend some properties of objects that you provide
- when you want to save resources by providing existing objects
Pros:
- avoid coupling of between creator and concrete type
- ability to add new types without breaking old code
- more control on code because there are one place where your objects are creating
Example:
Define Product
interface with single method GetCost()
:
1 2 3
| type Product interface { GetCost() int }
|
Define two concrete types of Product
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| type Phone struct { cost int }
func NewPhone(cost int) *Phone { return &Phone{cost} } func (p *Phone) GetCost() int { return p.cost }
const CarbonEmissionCost = 1000
type Car struct { cost int }
func NewCar(cost int) *Car { return &Car{cost} } func (c *Car) GetCost() int { return CarbonEmissionCost + c.cost }
|
Define factory that will create for us Product
types:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| type ProductType int
const ( PhoneType ProductType = iota CarType )
type ProductFactory struct { }
func (s *ProductFactory) NewProduct(p ProductType, cost int) Product { switch p { case PhoneType: return NewPhone(cost) case CarType: return NewCar(cost) } return nil }
|
Example of usage:
1 2 3 4 5 6 7 8 9
| func main() { products := []factory.Product{factory.NewCar(2000), factory.NewPhone(800)} totalCost := 0 for _, v := range products { totalCost += v.GetCost() } fmt.Printf("Total cost: %v$ ", totalCost) }
|