Metoda wytwórcza w języku Go
Metoda wytwórcza jest kreacyjnym wzorcem projektowym rozwiązującym problem tworzenia obiektów-produktów bez określania ich konkretnych klas.
Metoda wytwórcza definiuje metodę która ma służyć tworzeniu obiektów bez bezpośredniego wywoływania konstruktora (poprzez operator new). Podklasy mogą nadpisać tę metodę w celu zmiany klasy tworzonych obiektów.
Jeśli masz problem ze zrozumieniem różnicy pomiędzy poszczególnymi koncepcjami i wzorcami wytwórczymi, przeczytaj nasze Porównanie fabryk.
Przykład koncepcyjny
W Go nie da się zaimplementować klasycznego wzorca Metody wytwórczej z racji braku takich funkcjonalności języków obiektowych jak klasy i dziedziczenie. Możemy jednak zaimplementować jego okrojoną wersję - Fabrykę Prostą.
W poniższym przykładzie będziemy produkować różne rodzaje broni stosując strukturę fabryczną.
Zaczniemy od stworzenia interfejsu iGun definiującego wszystkie metody właściwe broniom. Mamy typ struktury gun implementujący interfejs iGun. Dwie konkretne bronie — ak47 i muszkiet zawierają strukturę broni i pośrednio implementują wszystkie metody iGun.
Struktura gunFactory służy za fabrykę tworzącą bronie wybranego typu na podstawie przekazanego jej argumentu. Klientem jest tu main.go. Zamiast pracować bezpośrednio z ak47 lub z muszkietem, zależna jest od gunFactory w zakresie generowania instancji różnych typów broni zależnie od parametrów-łańcuchów znaków.
iGun.go: Interfejs produktu
package main type IGun interface { setName(name string) setPower(power int) getName() string getPower() int } gun.go: Konkretny produkt
package main type Gun struct { name string power int } func (g *Gun) setName(name string) { g.name = name } func (g *Gun) getName() string { return g.name } func (g *Gun) setPower(power int) { g.power = power } func (g *Gun) getPower() int { return g.power } ak47.go: Konkretny produkt
package main type Ak47 struct { Gun } func newAk47() IGun { return &Ak47{ Gun: Gun{ name: "AK47 gun", power: 4, }, } } musket.go: Konkretny produkt
package main type musket struct { Gun } func newMusket() IGun { return &musket{ Gun: Gun{ name: "Musket gun", power: 1, }, } } gunFactory.go: Fabryka
package main import "fmt" func getGun(gunType string) (IGun, error) { if gunType == "ak47" { return newAk47(), nil } if gunType == "musket" { return newMusket(), nil } return nil, fmt.Errorf("Wrong gun type passed") } main.go: Kod klienta
package main import "fmt" func main() { ak47, _ := getGun("ak47") musket, _ := getGun("musket") printDetails(ak47) printDetails(musket) } func printDetails(g IGun) { fmt.Printf("Gun: %s", g.getName()) fmt.Println() fmt.Printf("Power: %d", g.getPower()) fmt.Println() } output.txt: Wynik działania
Gun: AK47 gun Power: 4 Gun: Musket gun Power: 1