![Abstract Factory](/images/patterns/cards/abstract-factory-mini.png?id=4c3927c446313a38ce77dfee38111e27)
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