![Factory Method](/images/patterns/cards/factory-method-mini.png?id=72619e9527893374b98a5913779ac167)
Factory Method を Go で
Factory Method は、 生成に関するデザインパターンの一つで、 具象クラスを指定することなく、 プロダクト (訳注: 本パターンでは、 生成されるモノのことを一般にプロダクトと呼びます) のオブジェクトを生成することを可能とします。
Factory Method では、 オブジェクトの生成において、 直接のコンストラクター呼び出し (new
演算子) 代わりに使用すべきメソッドを定義します。 サブクラスにおいてこのメソッドを上書きすることにより、 生成されるオブジェクトのクラスを変更します。
もし各種ファクトリー系のパターンやコンセプトの違いで迷った場合は、 ファクトリーの比較 をご覧ください。
概念的な例
Go には、 クラスや継承などの OOP 機能がないため、 Go で古典的な Factory Method パターンを実装することは不可能です。 ただし、 パターンの簡易版である単純ファクトリーなら実装できます。
この例では、 ファクトリー構造体を使用して、 多種の兵器を製造します。
最初に、 iGun
インターフェースを作成します。 これは、 銃が持つべき全メソッドを定義します。 gun
構造体は、 iGun インターフェースを実装します。 二つの具象銃、 ak47
と musket
は、 両方とも gun 構造体を埋め込み、 間接的に iGun
の全メソッドを実装します。
gunFactory
構造体はファクトリーとして機能し、 入力引数に応じて望みの種類の銃を作成します。 main.go< は、 クライアントです。 直接 ak47
や musket
と関わる代わりに、 種々の銃のインスタンスの作成を gunFactory
に頼ります。 文字列パラメーターが製造を管理します。
iGun.go: プロダクト・インターフェース
package main
type IGun interface {
setName(name string)
setPower(power int)
getName() string
getPower() int
}
gun.go: 具象プロダクト
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: 具象プロダクト
package main
type Ak47 struct {
Gun
}
func newAk47() IGun {
return &Ak47{
Gun: Gun{
name: "AK47 gun",
power: 4,
},
}
}
musket.go: 具象プロダクト
package main
type musket struct {
Gun
}
func newMusket() IGun {
return &musket{
Gun: Gun{
name: "Musket gun",
power: 1,
},
}
}
gunFactory.go: ファクトリー
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: クライアント・コード
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: 実行結果
Gun: AK47 gun
Power: 4
Gun: Musket gun
Power: 1