俺の新 Git コース見てよ! おーい!俺の新 Git コース見てよ! おーい!GitByBit.com に俺の新 Git コースあるよ、見てみ! おーい!Git をサクッと復習したい?GitByBit.com の俺の新コース見てみ!
Abstract Factory

Abstract Factory を Go で

Abstract Factory は、 生成に関するデザインパターンのひとつで、 具象クラスを指定することなく、 プロダクト (訳注: 本パターンでは、 生成されるモノのことを一般にプロダクトと呼びます) のファミリー全部を生成することを可能とします。

Abstract Factory は、 個々のプロダクト全部を作成するためのインターフェースを定義しますが、 実際のプロダクト作成の作業は、 具象クラスに委ねられます。 ファクトリーの型 (クラス) それぞれは、 特定のプロダクトの異種に対応します。

クライアント・コードは、 コンストラクター呼び出し (new 演算子) で直接プロダクトを作成する代わりにファクトリー・オブジェクトの作成メソッドを呼び出します。 ファクトリーはプロダクトの特定の異種に対応しているため、 すべてのプロダクトには互換性があります。

クライアント・コードは、 その抽象インターフェイスを通じてのみファクトリーやプロダクトとやりとりします。 このため、 クライアント・コードはファクトリー・オブジェクトによって作成された任意のプロダクトの異種と動作します。 プログラマーがやるべきことは、 新しい具象ファクトリー・クラスを作成し、 それをクライアント・コードに渡すことです。

もし各種ファクトリー系のパターンやコンセプトの違いで迷った場合は、 ファクトリーの比較 をご覧ください。

概念的な例

靴 1 足とシャツ 1 枚の二つの異なった製品の組み合わせであるスポーツ・キットを買う必要があるとします。 あなたは、 同じブランドのスポーツ・キットを購入したいと思っています。

もしこれをコードに転換したければ、 Abstract Factory が、 常に互いにマッチするプロダクトの組を作成するのに役立ちます。

iSportsFactory.go: Abstract Factory インターフェース

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: 具象ファクトリー

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: 具象ファクトリー

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: 抽象プロダクト

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: 具象プロダクト

package main

type AdidasShoe struct {
	Shoe
}

nikeShoe.go: 具象プロダクト

package main

type NikeShoe struct {
	Shoe
}

iShirt.go: 抽象プロダクト

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: 具象プロダクト

package main

type AdidasShirt struct {
	Shirt
}

nikeShirt.go: 具象プロダクト

package main

type NikeShirt struct {
	Shirt
}

main.go: クライアント・コード

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: 実行結果

Logo: nike
Size: 14
Logo: nike
Size: 14
Logo: adidas
Size: 14
Logo: adidas
Size: 14

他言語での Abstract Factory

Abstract Factory を C# で Abstract Factory を C++ で Abstract Factory を Java で Abstract Factory を PHP で Abstract Factory を Python で Abstract Factory を Ruby で Abstract Factory を Rust で Abstract Factory を Swift で Abstract Factory を TypeScript で