Sobes.tech
Middle

Háblame del patrón Factory.

sobes.tech AI

Respuesta de la IA

La fábrica es un patrón de diseño creacional que proporciona una interfaz común para crear objetos en la superclase, mientras que las subclases pueden modificar el tipo de objetos creados.

  • Fábrica simple (Simple Factory): No es un patrón en su forma pura, sino más bien una idiomática. Una clase con un método que crea objetos basándose en los parámetros de entrada.

    package main
    
    import "fmt"
    
    type Product interface {
    	Use()
    }
    
    type ConcreteProductA struct{}
    
    func (p *ConcreteProductA) Use() {
    	fmt.Println("Usando Producto Concreto A")
    }
    
    type ConcreteProductB struct{}
    
    func (p *ConcreteProductB) Use() {
    	fmt.Println("Usando Producto Concreto 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()
    }
    
  • Método de fábrica (Factory Method): Define una interfaz para crear un objeto, pero permite que las subclases decidan qué clase instanciar.

    package main
    
    import "fmt"
    
    // Interfaz de producto
    type Product interface {
    	Operation() string
    }
    
    // Producto concreto A
    type ConcreteProduct1 struct{}
    
    func (p *ConcreteProduct1) Operation() string {
    	return "Resultado del ProductoConcreto1"
    }
    
    // Producto concreto B
    type ConcreteProduct2 struct{}
    
    func (p *ConcreteProduct2) Operation() string {
    	return "Resultado del ProductoConcreto2"
    }
    
    // Interfaz del creador
    type Creator interface {
    	FactoryMethod() Product
    	SomeOperation() string
    }
    
    // Estructura base del creador
    type BaseCreator struct{}
    
    func (bc *BaseCreator) SomeOperation() string {
    	// Llamada al método de fábrica para obtener un objeto de producto
    	product := bc.FactoryMethod()
    	// Uso del producto
    	result := "El código del creador ha trabajado con " + product.Operation()
    	return result
    }
    
    // Creador concreto A
    type ConcreteCreator1 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator1) FactoryMethod() Product {
    	return &ConcreteProduct1{} // Crea Producto concreto A
    }
    
    // Creador concreto B
    type ConcreteCreator2 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator2) FactoryMethod() Product {
    	return &ConcreteProduct2{} // Crea Producto concreto B
    }
    
    func main() {
    	// Ejemplo de uso
    	creator1 := &ConcreteCreator1{}
    	fmt.Println(creator1.SomeOperation())
    
    	creator2 := &ConcreteCreator2{}
    	fmt.Println(creator2.SomeOperation())
    }
    
  • Fábrica abstracta (Abstract Factory): Proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.

    package main
    
    import "fmt"
    
    // Interfaz de producto A
    type AbstractProductA interface {
    	UseProductA() string
    }
    
    // Producto A1 concreto
    type ConcreteProductA1 struct{}
    
    func (*ConcreteProductA1) UseProductA() string {
    	return "El resultado del producto A1."
    }
    
    // Producto A2 concreto
    type ConcreteProductA2 struct{}
    
    func (*ConcreteProductA2) UseProductA() string {
    	return "El resultado del producto A2."
    }
    
    // Interfaz de producto B
    type AbstractProductB interface {
    	UseProductB() string
    	AnotherFunctionB(collaborator AbstractProductA) string // Interacción con producto A
    }
    
    // Producto B1 concreto
    type ConcreteProductB1 struct{}
    
    func (*ConcreteProductB1) UseProductB() string {
    	return "El resultado del producto B1."
    }
    
    // Interacción B1 con cualquier tipo de AbstractProductA
    func (*ConcreteProductB1) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("El resultado del B1 colaborando con el (%s)", result)
    }
    
    // Producto B2 concreto
    type ConcreteProductB2 struct{}
    
    func (*ConcreteProductB2) UseProductB() string {
    	return "El resultado del producto B2."
    }
    
    // Interacción B2 con cualquier tipo de AbstractProductA
    func (*ConcreteProductB2) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("El resultado del B2 colaborando con el (%s)", result)
    }
    
    // Interfaz de la fábrica abstracta
    type AbstractFactory interface {
    	CreateProductA() AbstractProductA
    	CreateProductB() AbstractProductB
    }
    
    // Fábrica concreta 1
    type ConcreteFactory1 struct{}
    
    func (*ConcreteFactory1) CreateProductA() AbstractProductA {
    	return &ConcreteProductA1{}
    }
    
    func (*ConcreteFactory1) CreateProductB() AbstractProductB {
    	return &ConcreteProductB1{}
    }
    
    // Fábrica concreta 2
    type ConcreteFactory2 struct{}
    
    func (*ConcreteFactory2) CreateProductA() AbstractProductA {
    	return &ConcreteProductA2{}
    }
    
    func (*ConcreteFactory2) CreateProductB() AbstractProductB {
    	return &ConcreteProductB2{}
    }
    
    // Código cliente que trabaja con la fábrica
    func ClientCode(factory AbstractFactory) {
    	productA := factory.CreateProductA()
    	productB := factory.CreateProductB()
    
    	fmt.Println(productB.UseProductB())
    	fmt.Println(productB.AnotherFunctionB(productA))
    }
    
    func main() {
    	fmt.Println("Cliente: Probando código cliente con el primer tipo de fábrica:")
    	ClientCode(&ConcreteFactory1{})
    
    	fmt.Println("Cliente: Probando el mismo código cliente con el segundo tipo de fábrica:")
    	ClientCode(&ConcreteFactory2{})
    }
    

La principal diferencia entre el método de fábrica y la fábrica abstracta: El método de fábrica crea productos individuales, mientras que la fábrica abstracta crea familias de productos.

Nombre del patrón Descripción Cuándo usar
Fábrica simple Método en una clase para crear objetos de diferentes tipos. Para crear objetos simples sin necesidad de una jerarquía de fábricas.
Método de fábrica Interfaz para crear un objeto, permitiendo que las subclases decidan qué clase instanciar. Cuando una clase no puede predecir el tipo de objetos que debe crear.
Fábrica abstracta Interfaz para crear familias de objetos relacionados. Cuando el sistema debe ser independiente del modo en que se crean y representan sus productos.

El patrón Fábrica fomenta un acoplamiento débil del código y facilita la adición de nuevos tipos de productos sin modificar el código cliente.