
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