Tell me about the Factory pattern.
sobes.tech AI
Answer from AI
Factory is a creational design pattern that provides a common interface for creating objects in a superclass, while subclasses can alter the type of objects that will be created.
-
Simple Factory: Not a pattern in its pure form, more of an idiom. A class with a method that creates objects based on input parameters.
package main import "fmt" type Product interface { Use() } type ConcreteProductA struct{} func (p *ConcreteProductA) Use() { fmt.Println("Using Concrete Product A") } type ConcreteProductB struct{} func (p *ConcreteProductB) Use() { fmt.Println("Using Concrete Product B") } type SimpleFactory struct{} func (f *SimpleFactory) CreateProduct(t string) Product { switch t { case "A": return &ConcreteProductA{} case "B": return &ConcreteProductB{} default: return nil } } func main() { factory := SimpleFactory{} productA := factory.CreateProduct("A") productA.Use() productB := factory.CreateProduct("B") productB.Use() } -
Factory Method: Defines an interface for creating an object, but allows subclasses to decide which class to instantiate.
package main import "fmt" // Product interface type Product interface { Operation() string } // Concrete Product A type ConcreteProduct1 struct{} func (p *ConcreteProduct1) Operation() string { return "Result of the ConcreteProduct1" } // Concrete Product B type ConcreteProduct2 struct{} func (p *ConcreteProduct2) Operation() string { return "Result of the ConcreteProduct2" } // Creator interface type Creator interface { FactoryMethod() Product SomeOperation() string } // Base Creator type BaseCreator struct{} func (bc *BaseCreator) SomeOperation() string { // Call the factory method to get a product product := bc.FactoryMethod() // Use the product result := "Creator: The same creator's code has just worked with " + product.Operation() return result } // Concrete Creator 1 type ConcreteCreator1 struct { BaseCreator } func (cc *ConcreteCreator1) FactoryMethod() Product { return &ConcreteProduct1{} // Creates Concrete Product A } // Concrete Creator 2 type ConcreteCreator2 struct { BaseCreator } func (cc *ConcreteCreator2) FactoryMethod() Product { return &ConcreteProduct2{} // Creates Concrete Product B } func main() { // Usage example creator1 := &ConcreteCreator1{} fmt.Println(creator1.SomeOperation()) creator2 := &ConcreteCreator2{} fmt.Println(creator2.SomeOperation()) } -
Abstract Factory: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
package main import "fmt" // Product A interface type AbstractProductA interface { UseProductA() string } // Concrete Product A1 type ConcreteProductA1 struct{} func (*ConcreteProductA1) UseProductA() string { return "The result of the product A1." } // Concrete Product A2 type ConcreteProductA2 struct{} func (*ConcreteProductA2) UseProductA() string { return "The result of the product A2." } // Product B interface type AbstractProductB interface { UseProductB() string AnotherFunctionB(collaborator AbstractProductA) string // Interaction with product A } // Concrete Product B1 type ConcreteProductB1 struct{} func (*ConcreteProductB1) UseProductB() string { return "The result of the product B1." } // B1 interaction with any AbstractProductA func (*ConcreteProductB1) AnotherFunctionB(collaborator AbstractProductA) string { result := collaborator.UseProductA() return fmt.Sprintf("The result of the B1 collaborating with the (%s)", result) } // Concrete Product B2 type ConcreteProductB2 struct{} func (*ConcreteProductB2) UseProductB() string { return "The result of the product B2." } // B2 interaction with any AbstractProductA func (*ConcreteProductB2) AnotherFunctionB(collaborator AbstractProductA) string { result := collaborator.UseProductA() return fmt.Sprintf("The result of the B2 collaborating with the (%s)", result) } // Abstract Factory interface type AbstractFactory interface { CreateProductA() AbstractProductA CreateProductB() AbstractProductB } // Concrete Factory 1 type ConcreteFactory1 struct{} func (*ConcreteFactory1) CreateProductA() AbstractProductA { return &ConcreteProductA1{} } func (*ConcreteFactory1) CreateProductB() AbstractProductB { return &ConcreteProductB1{} } // Concrete Factory 2 type ConcreteFactory2 struct{} func (*ConcreteFactory2) CreateProductA() AbstractProductA { return &ConcreteProductA2{} } func (*ConcreteFactory2) CreateProductB() AbstractProductB { return &ConcreteProductB2{} } // Client code working with factory func ClientCode(factory AbstractFactory) { productA := factory.CreateProductA() productB := factory.CreateProductB() fmt.Println(productB.UseProductB()) fmt.Println(productB.AnotherFunctionB(productA)) } func main() { fmt.Println("Client: Testing client code with the first factory type:") ClientCode(&ConcreteFactory1{}) fmt.Println("Client: Testing the same client code with the second factory type:") ClientCode(&ConcreteFactory2{}) }
The main difference between Factory Method and Abstract Factory: Factory Method creates individual products, while Abstract Factory creates families of products.
| Pattern Name | Description | When to use |
|---|---|---|
| Simple Factory | Method in a single class for creating different types of objects. | For simple object creation without the need for a factory hierarchy. |
| Factory Method | Interface for creating an object, allowing subclasses to decide which class to instantiate. | When the class cannot predict the type of objects it should create. |
| Abstract Factory | Interface for creating families of related objects. | When the system should be independent of how its products are created and represented. |
The Factory pattern promotes loose coupling of code and makes it easier to add new product types without changing client code.