Sobes.tech
Middle

Opowiedz o wzorcu Factory.

sobes.tech AI

Odpowiedź od AI

Fabrika to wzorzec projektowy tworzenia, który zapewnia wspólny interfejs do tworzenia obiektów w superklasie, podczas gdy podklasy mogą zmieniać typ tworzonych obiektów.

  • Prosta fabryka (Simple Factory): Nie jest to wzorzec w czystej formie, raczej idiom. Klasa z metodą tworzącą obiekty na podstawie parametrów wejściowych.

    package main
    
    import "fmt"
    
    type Product interface {
    	Use()
    }
    
    type ConcreteProductA struct{}
    
    func (p *ConcreteProductA) Use() {
    	fmt.Println("Używanie produktu Concrete A")
    }
    
    type ConcreteProductB struct{}
    
    func (p *ConcreteProductB) Use() {
    	fmt.Println("Używanie produktu 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()
    }
    
  • Metoda fabryczna (Factory Method): Definiuje interfejs do tworzenia obiektu, ale pozwala podklasom decydować, którą klasę zainstancjonować.

    package main
    
    import "fmt"
    
    // Interfejs produktu
    type Product interface {
    	Operation() string
    }
    
    // Konkretne produkty A
    type ConcreteProduct1 struct{}
    
    func (p *ConcreteProduct1) Operation() string {
    	return "Wynik ConcreteProduct1"
    }
    
    // Konkretne produkty B
    type ConcreteProduct2 struct{}
    
    func (p *ConcreteProduct2) Operation() string {
    	return "Wynik ConcreteProduct2"
    }
    
    // Interfejs twórcy
    type Creator interface {
    	FactoryMethod() Product
    	SomeOperation() string
    }
    
    // Podstawowa struktura twórcy
    type BaseCreator struct{}
    
    func (bc *BaseCreator) SomeOperation() string {
    	// Wywołanie metody fabrycznej w celu uzyskania obiektu produktu
    	product := bc.FactoryMethod()
    	// Użycie produktu
    	result := "Twórca: Ten sam kod twórcy właśnie pracował z " + product.Operation()
    	return result
    }
    
    // Konkretni twórcy
    type ConcreteCreator1 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator1) FactoryMethod() Product {
    	return &ConcreteProduct1{} // Tworzy konkretny produkt A
    }
    
    type ConcreteCreator2 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator2) FactoryMethod() Product {
    	return &ConcreteProduct2{} // Tworzy konkretny produkt B
    }
    
    func main() {
    	// Przykład użycia
    	creator1 := &ConcreteCreator1{}
    	fmt.Println(creator1.SomeOperation())
    
    	creator2 := &ConcreteCreator2{}
    	fmt.Println(creator2.SomeOperation())
    }
    
  • Fabrika abstrakcyjna (Abstract Factory): Zapewnia interfejs do tworzenia rodzin powiązanych lub zależnych obiektów bez wskazywania ich konkretnych klas.

    package main
    
    import "fmt"
    
    // Interfejs produktu A
    type AbstractProductA interface {
    	UseProductA() string
    }
    
    // Konkretne produkty A1
    type ConcreteProductA1 struct{}
    
    func (*ConcreteProductA1) UseProductA() string {
    	return "Wynik produktu A1."
    }
    
    // Konkretne produkty A2
    type ConcreteProductA2 struct{}
    
    func (*ConcreteProductA2) UseProductA() string {
    	return "Wynik produktu A2."
    }
    
    // Interfejs produktu B
    type AbstractProductB interface {
    	UseProductB() string
    	AnotherFunctionB(collaborator AbstractProductA) string // Interakcja z produktem A
    }
    
    // Konkretne produkty B1
    type ConcreteProductB1 struct{}
    
    func (*ConcreteProductB1) UseProductB() string {
    	return "Wynik produktu B1."
    }
    
    // Interakcja B1 z dowolnym typem AbstractProductA
    func (*ConcreteProductB1) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("Wynik B1 współpracującego z (%s)", result)
    }
    
    // Konkretne produkty B2
    type ConcreteProductB2 struct{}
    
    func (*ConcreteProductB2) UseProductB() string {
    	return "Wynik produktu B2."
    }
    
    // Interakcja B2 z dowolnym typem AbstractProductA
    func (*ConcreteProductB2) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("Wynik B2 współpracującego z (%s)", result)
    }
    
    // Interfejs fabryki abstrakcyjnej
    type AbstractFactory interface {
    	CreateProductA() AbstractProductA
    	CreateProductB() AbstractProductB
    }
    
    // Konkretna fabryka 1
    type ConcreteFactory1 struct{}
    
    func (*ConcreteFactory1) CreateProductA() AbstractProductA {
    	return &ConcreteProductA1{}
    }
    
    func (*ConcreteFactory1) CreateProductB() AbstractProductB {
    	return &ConcreteProductB1{}
    }
    
    // Konkretna fabryka 2
    type ConcreteFactory2 struct{}
    
    func (*ConcreteFactory2) CreateProductA() AbstractProductA {
    	return &ConcreteProductA2{}
    }
    
    func (*ConcreteFactory2) CreateProductB() AbstractProductB {
    	return &ConcreteProductB2{}
    }
    
    // Kod klienta pracujący z fabryką
    func ClientCode(factory AbstractFactory) {
    	productA := factory.CreateProductA()
    	productB := factory.CreateProductB()
    
    	fmt.Println(productB.UseProductB())
    	fmt.Println(productB.AnotherFunctionB(productA))
    }
    
    func main() {
    	fmt.Println("Klient: Testowanie kodu klienta z pierwszym typem fabryki:")
    	ClientCode(&ConcreteFactory1{})
    
    	fmt.Println("Klient: Testowanie tego samego kodu klienta z drugim typem fabryki:")
    	ClientCode(&ConcreteFactory2{})
    }
    

Główna różnica między Factory Method a Abstract Factory: Factory Method tworzy pojedyncze produkty, podczas gdy Abstract Factory tworzy rodziny produktów.

Nazwa wzorca Opis Kiedy go używać
Prosta fabryka Metoda w jednej klasie do tworzenia obiektów różnych typów. Do prostego tworzenia obiektów bez konieczności hierarchii fabryk.
Metoda fabryczna Interfejs do tworzenia obiektu, pozwalający podklasom decydować, którą klasę zainstancjonować. Gdy klasa nie może przewidzieć typu obiektów, które musi utworzyć.
Fabryka abstrakcyjna Interfejs do tworzenia powiązanych rodzin obiektów. Gdy system musi być niezależny od sposobu tworzenia i reprezentacji jego produktów.

Wzorzec fabryki sprzyja luźnemu powiązaniu kodu i ułatwia dodawanie nowych typów produktów bez zmiany kodu klienta.