Hura! Mamy wreszcie przyjemność udostępnić wam polską wersję! Zapraszamy do przesyłania wiadomości z waszymi uwagami i informacjami o zauważonych błędach.
Fabryka abstrakcyjna

Fabryka abstrakcyjna w języku Go

Fabryka abstrakcyjna jest kreacyjnym wzorcem projektowym, który pozwala tworzyć rodziny spokrewnionych ze sobą obiektów bez określania ich konkretnych klas.

Fabryka abstrakcyjna definiuje interfejs służący tworzeniu poszczególnych produktów, ale pozostawia faktyczne tworzenie produktów konkretnym klasom fabrycznym. Każdy typ fabryki odpowiada jednemu z wariantów produktu.

Kod klienta wywołuje metody kreacyjne obiektu fabrycznego zamiast tworzyć produkty bezpośrednio — wywołując konstruktor (za pomocą operatora new). Skoro dana fabryka odpowiada jednemu z wariantów produktu, to wszystkie jej produkty będą ze sobą kompatybilne.

Kod klienta współpracuje z fabrykami i produktami wyłącznie poprzez ich abstrakcyjne interfejsy. Dzięki temu jeden klient jest kompatybilny z wieloma różnymi produktami. Wystarczy stworzyć nową konkretną klasę fabryczną i przekazać ją kodowi klienta.

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

Powiedzmy, że chcesz kupić dwa stroje gimnastyczne składające się z pary butów i podkoszulka. Najlepiej, gdyby wszystkie elementy stroju były tej samej marki.

Jeśli chcemy zamienić to na kod, fabryka abstrakcyjna pozwoli nam tworzyć produkty zawsze do siebie pasujące.

iSportsFactory.go: Interfejs fabryki abstrakcyjnej

package main

import "fmt"

type iSportsFactory interface {
	makeShoe() iShoe
	makeShirt() iShirt
}

func getSportsFactory(brand string) (iSportsFactory, error) {
	if brand == "adidas" {
		return &adidas{}, nil
	}

	if brand == "nike" {
		return &nike{}, nil
	}

	return nil, fmt.Errorf("Wrong brand type passed")
}

adidas.go: Konkretna fabryka

package main

type adidas struct {
}

func (a *adidas) makeShoe() iShoe {
	return &adidasShoe{
		shoe: shoe{
			logo: "adidas",
			size: 14,
		},
	}
}

func (a *adidas) makeShirt() iShirt {
	return &adidasShirt{
		shirt: shirt{
			logo: "adidas",
			size: 14,
		},
	}
}

nike.go: Konkretna fabryka

package main

type nike struct {
}

func (n *nike) makeShoe() iShoe {
	return &nikeShoe{
		shoe: shoe{
			logo: "nike",
			size: 14,
		},
	}
}

func (n *nike) makeShirt() iShirt {
	return &nikeShirt{
		shirt: shirt{
			logo: "nike",
			size: 14,
		},
	}
}

iShoe.go: Produkt abstrakcyjny

package main

type iShoe interface {
	setLogo(logo string)
	setSize(size int)
	getLogo() string
	getSize() int
}

type shoe struct {
	logo string
	size int
}

func (s *shoe) setLogo(logo string) {
	s.logo = logo
}

func (s *shoe) getLogo() string {
	return s.logo
}

func (s *shoe) setSize(size int) {
	s.size = size
}

func (s *shoe) getSize() int {
	return s.size
}

adidasShoe.go: Konkretny produkt

package main

type adidasShoe struct {
	shoe
}

nikeShoe.go: Konkretny produkt

package main

type nikeShoe struct {
	shoe
}

iShirt.go: Produkt abstrakcyjny

package main

type iShirt interface {
	setLogo(logo string)
	setSize(size int)
	getLogo() string
	getSize() int
}

type shirt struct {
	logo string
	size int
}

func (s *shirt) setLogo(logo string) {
	s.logo = logo
}

func (s *shirt) getLogo() string {
	return s.logo
}

func (s *shirt) setSize(size int) {
	s.size = size
}

func (s *shirt) getSize() int {
	return s.size
}

adidasShirt.go: Konkretny produkt

package main

type adidasShirt struct {
	shirt
}

nikeShirt.go: Konkretny produkt

package main

type nikeShirt struct {
	shirt
}

main.go: Kod klienta

package main

import "fmt"

func main() {
	adidasFactory, _ := getSportsFactory("adidas")
	nikeFactory, _ := getSportsFactory("nike")

	nikeShoe := nikeFactory.makeShoe()
	nikeShirt := nikeFactory.makeShirt()

	adidasShoe := adidasFactory.makeShoe()
	adidasShirt := adidasFactory.makeShirt()

	printShoeDetails(nikeShoe)
	printShirtDetails(nikeShirt)

	printShoeDetails(adidasShoe)
	printShirtDetails(adidasShirt)
}

func printShoeDetails(s iShoe) {
	fmt.Printf("Logo: %s", s.getLogo())
	fmt.Println()
	fmt.Printf("Size: %d", s.getSize())
	fmt.Println()
}

func printShirtDetails(s iShirt) {
	fmt.Printf("Logo: %s", s.getLogo())
	fmt.Println()
	fmt.Printf("Size: %d", s.getSize())
	fmt.Println()
}

output.txt: Wynik działania

Logo: nike
Size: 14
Logo: nike
Size: 14
Logo: adidas
Size: 14
Logo: adidas
Size: 14
Na podstawie: Golang By Example

Fabryka abstrakcyjna w innych językach

Wzorce projektowe: Fabryka abstrakcyjna w języku Java Wzorce projektowe: Fabryka abstrakcyjna w języku C# Wzorce projektowe: Fabryka abstrakcyjna w języku C++ Wzorce projektowe: Fabryka abstrakcyjna w języku PHP Wzorce projektowe: Fabryka abstrakcyjna w języku Python Wzorce projektowe: Fabryka abstrakcyjna w języku Ruby Wzorce projektowe: Fabryka abstrakcyjna w języku Swift Wzorce projektowe: Fabryka abstrakcyjna w języku TypeScript