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