Sobes.tech
Middle

Parlez-moi du pattern Factory.

sobes.tech IA

Réponse de l'IA

Une usine est un patron de conception creational qui fournit une interface commune pour créer des objets dans la superclasse, tandis que les sous-classes peuvent modifier le type d'objets créés.

  • Fournisseur simple (Simple Factory): Ce n'est pas un pattern à part entière, mais plutôt une idiome. Une classe avec une méthode qui crée des objets en fonction des paramètres d'entrée.

    package main
    
    import "fmt"
    
    type Product interface {
    	Use()
    }
    
    type ConcreteProductA struct{}
    
    func (p *ConcreteProductA) Use() {
    	fmt.Println("Utilisation du Produit Concret A")
    }
    
    type ConcreteProductB struct{}
    
    func (p *ConcreteProductB) Use() {
    	fmt.Println("Utilisation du Produit Concret 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éthode de la fabrique (Factory Method): Définit une interface pour créer un objet, mais permet aux sous-classes de décider quelle classe instancier.

    package main
    
    import "fmt"
    
    // Interface du produit
    type Product interface {
    	Operation() string
    }
    
    // Produit concret A
    type ConcreteProduct1 struct{}
    
    func (p *ConcreteProduct1) Operation() string {
    	return "Résultat du ConcreteProduct1"
    }
    
    // Produit concret B
    type ConcreteProduct2 struct{}
    
    func (p *ConcreteProduct2) Operation() string {
    	return "Résultat du ConcreteProduct2"
    }
    
    // Interface du créateur
    type Creator interface {
    	FactoryMethod() Product
    	SomeOperation() string
    }
    
    // Structure de base du créateur
    type BaseCreator struct{}
    
    func (bc *BaseCreator) SomeOperation() string {
    	// Appel de la méthode de fabrique pour obtenir un objet produit
    	product := bc.FactoryMethod()
    	// Utilisation du produit
    	result := "Le code du créateur a travaillé avec " + product.Operation()
    	return result
    }
    
    // Créateur concret A
    type ConcreteCreator1 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator1) FactoryMethod() Product {
    	return &ConcreteProduct1{} // Crée un produit concret A
    }
    
    // Créateur concret B
    type ConcreteCreator2 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator2) FactoryMethod() Product {
    	return &ConcreteProduct2{} // Crée un produit concret B
    }
    
    func main() {
    	// Exemple d'utilisation
    	creator1 := &ConcreteCreator1{}
    	fmt.Println(creator1.SomeOperation())
    
    	creator2 := &ConcreteCreator2{}
    	fmt.Println(creator2.SomeOperation())
    }
    
  • Fournisseur abstrait (Abstract Factory): Fournit une interface pour créer des familles d'objets liés ou dépendants sans spécifier leurs classes concrètes.

    package main
    
    import "fmt"
    
    // Interface du produit A
    type AbstractProductA interface {
    	UseProductA() string
    }
    
    // Produit A1 concret
    type ConcreteProductA1 struct{}
    
    func (*ConcreteProductA1) UseProductA() string {
    	return "Le résultat du produit A1."
    }
    
    // Produit A2 concret
    type ConcreteProductA2 struct{}
    
    func (*ConcreteProductA2) UseProductA() string {
    	return "Le résultat du produit A2."
    }
    
    // Interface du produit B
    type AbstractProductB interface {
    	UseProductB() string
    	AnotherFunctionB(collaborator AbstractProductA) string // Interaction avec le produit A
    }
    
    // Produit B1 concret
    type ConcreteProductB1 struct{}
    
    func (*ConcreteProductB1) UseProductB() string {
    	return "Le résultat du produit B1."
    }
    
    // Interaction B1 avec n'importe quel type d'AbstractProductA
    func (*ConcreteProductB1) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("Le résultat du B1 collaborant avec le (%s)", result)
    }
    
    // Produit B2 concret
    type ConcreteProductB2 struct{}
    
    func (*ConcreteProductB2) UseProductB() string {
    	return "Le résultat du produit B2."
    }
    
    // Interaction B2 avec n'importe quel type d'AbstractProductA
    func (*ConcreteProductB2) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("Le résultat du B2 collaborant avec le (%s)", result)
    }
    
    // Interface de la fabrique abstraite
    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.