Sobes.tech
Middle

Parla del pattern Factory.

sobes.tech AI

Risposta dell'AI

La fabbrica è un pattern di creazione che fornisce un'interfaccia comune per la creazione di oggetti nella superclasse, mentre le sottoclassi possono modificare il tipo di oggetti creati.

  • Factory Semplice (Simple Factory): Non è un pattern nel senso più puro, piuttosto un'idioma. Una classe con un metodo che crea oggetti in base ai parametri di input.

    package main
    
    import "fmt"
    
    type Product interface {
    	Use()
    }
    
    type ConcreteProductA struct{}
    
    func (p *ConcreteProductA) Use() {
    	fmt.Println("Utilizzo del Prodotto Concrete A")
    }
    
    type ConcreteProductB struct{}
    
    func (p *ConcreteProductB) Use() {
    	fmt.Println("Utilizzo del Prodotto Concrete 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 (Metodo Factory): Definisce un'interfaccia per la creazione di un oggetto, ma permette alle sottoclassi di decidere quale classe istanziare.

    package main
    
    import "fmt"
    
    // Interfaccia del prodotto
    type Product interface {
    	Operation() string
    }
    
    // Prodotto concreto A
    type ConcreteProduct1 struct{}
    
    func (p *ConcreteProduct1) Operation() string {
    	return "Risultato del ConcreteProduct1"
    }
    
    // Prodotto concreto B
    type ConcreteProduct2 struct{}
    
    func (p *ConcreteProduct2) Operation() string {
    	return "Risultato del ConcreteProduct2"
    }
    
    // Interfaccia del creatore
    type Creator interface {
    	FactoryMethod() Product
    	SomeOperation() string
    }
    
    // Struttura base del creatore
    type BaseCreator struct{}
    
    func (bc *BaseCreator) SomeOperation() string {
    	// Chiamata al metodo factory per ottenere l'oggetto prodotto
    	product := bc.FactoryMethod()
    	// Uso del prodotto
    	result := "Creator: Lo stesso codice del creatore ha appena lavorato con " + product.Operation()
    	return result
    }
    
    // Creatore concreto A
    type ConcreteCreator1 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator1) FactoryMethod() Product {
    	return &ConcreteProduct1{} // Crea il Prodotto concreto A
    }
    
    // Creatore concreto B
    type ConcreteCreator2 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator2) FactoryMethod() Product {
    	return &ConcreteProduct2{} // Crea il Prodotto concreto B
    }
    
    func main() {
    	// Esempio di utilizzo
    	creator1 := &ConcreteCreator1{}
    	fmt.Println(creator1.SomeOperation())
    
    	creator2 := &ConcreteCreator2{}
    	fmt.Println(creator2.SomeOperation())
    }
    
  • Abstract Factory (Fattoria Astratta): Fornisce un'interfaccia per la creazione di famiglie di oggetti correlati o dipendenti senza specificarne le classi concrete.

    package main
    
    import "fmt"
    
    // Interfaccia del prodotto A
    type AbstractProductA interface {
    	UseProductA() string
    }
    
    // Prodotto A1 concreto
    type ConcreteProductA1 struct{}
    
    func (*ConcreteProductA1) UseProductA() string {
    	return "Il risultato del prodotto A1."
    }
    
    // Prodotto A2 concreto
    type ConcreteProductA2 struct{}
    
    func (*ConcreteProductA2) UseProductA() string {
    	return "Il risultato del prodotto A2."
    }
    
    // Interfaccia del prodotto B
    type AbstractProductB interface {
    	UseProductB() string
    	AnotherFunctionB(collaborator AbstractProductA) string // Interazione con il prodotto A
    }
    
    // Prodotto B1 concreto
    type ConcreteProductB1 struct{}
    
    func (*ConcreteProductB1) UseProductB() string {
    	return "Il risultato del prodotto B1."
    }
    
    // Interazione B1 con qualsiasi tipo di AbstractProductA
    func (*ConcreteProductB1) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("Il risultato della collaborazione B1 con (%s)", result)
    }
    
    // Prodotto B2 concreto
    type ConcreteProductB2 struct{}
    
    func (*ConcreteProductB2) UseProductB() string {
    	return "Il risultato del prodotto B2."
    }
    
    // Interazione B2 con qualsiasi tipo di AbstractProductA
    func (*ConcreteProductB2) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("Il risultato della collaborazione B2 con (%s)", result)
    }
    
    // Interfaccia della fabbrica astratta
    type AbstractFactory interface {
    	CreateProductA() AbstractProductA
    	CreateProductB() AbstractProductB
    }
    
    // Fabbrica concreta 1
    type ConcreteFactory1 struct{}
    
    func (*ConcreteFactory1) CreateProductA() AbstractProductA {
    	return &ConcreteProductA1{}
    }
    
    func (*ConcreteFactory1) CreateProductB() AbstractProductB {
    	return &ConcreteProductB1{}
    }
    
    // Fabbrica concreta 2
    type ConcreteFactory2 struct{}
    
    func (*ConcreteFactory2) CreateProductA() AbstractProductA {
    	return &ConcreteProductA2{}
    }
    
    func (*ConcreteFactory2) CreateProductB() AbstractProductB {
    	return &ConcreteProductB2{}
    }
    
    // Codice cliente che lavora con la fabbrica
    func ClientCode(factory AbstractFactory) {
    	productA := factory.CreateProductA()
    	productB := factory.CreateProductB()
    
    	fmt.Println(productB.UseProductB())
    	fmt.Println(productB.AnotherFunctionB(productA))
    }
    
    func main() {
    	fmt.Println("Cliente: Test del codice cliente con il primo tipo di fabbrica:")
    	ClientCode(&ConcreteFactory1{})
    
    	fmt.Println("Cliente: Test dello stesso codice cliente con il secondo tipo di fabbrica:")
    	ClientCode(&ConcreteFactory2{})
    }
    

La principale differenza tra Factory Method e Abstract Factory: Factory Method crea singoli prodotti, mentre Abstract Factory crea famiglie di prodotti.

Nome del pattern Descrizione Quando usarlo
Factory Semplice Metodo in una classe per creare oggetti di diversi tipi. Per la creazione semplice di oggetti senza la necessità di una gerarchia di fabbriche.
Factory Method Interfaccia per creare un oggetto, consentendo alle sottoclassi di decidere quale classe istanziare. Quando una classe non può prevedere il tipo di oggetti che deve creare.
Abstract Factory Interfaccia per creare famiglie di oggetti correlati. Quando il sistema deve essere indipendente dal modo in cui vengono creati e rappresentati i suoi prodotti.

Il pattern Factory favorisce un basso accoppiamento del codice e facilita l'aggiunta di nuovi tipi di prodotti senza modificare il codice cliente.