![Builder](/images/patterns/cards/builder-mini.png?id=19b95fd05e6469679752c0554b116815)
Builder を Go で
Builder は生成に関するデザインパターンの一つで、 複雑なオブジェクトを段階的に構築することができます。
他の生成に関するパターンとは異なり、 Builder ではプロダクト (訳注: 本パターンでは、 生成されるモノのことを一般にプロダクトと呼びます) が共通のインターフェースを持つ必要はありません。 このため、 同じ構築の手続きを経て、 異なるプロダクトを作成することができます。
概念的な例
Builder パターンは、 目的とするプロダクトが複雑で、 完成まで多くのステップが必要な時に使われます。 この場合、 単一の超巨大なコンストラクターを持つよりも、 いくつかの構築メソッドを持つ方がシンプルです。 多段階での構築方法では、 未完成の、 安全性に欠けるプロダクトがクライアントから利用可能になってしまうという潜在的問題がありますが、 Builder パターンを使うと、 構築が完了するまで、 プロダクトは外部に非公開の状態が保たれます。
以下のコードでは、 異なる種類の家 (igloo
と normalHouse
) が、 iglooBuilder
と normalBuilder
によって構築されています。 どちらの種類の家も、 同じ構築ステップを使います。 ディレクター構造体は、 構築過程を組織化する役に立ちます。
iBuilder.go: ビルダーのインターフェース
package main
type IBuilder interface {
setWindowType()
setDoorType()
setNumFloor()
getHouse() House
}
func getBuilder(builderType string) IBuilder {
if builderType == "normal" {
return newNormalBuilder()
}
if builderType == "igloo" {
return newIglooBuilder()
}
return nil
}
normalBuilder.go: 具象ビルダー
package main
type NormalBuilder struct {
windowType string
doorType string
floor int
}
func newNormalBuilder() *NormalBuilder {
return &NormalBuilder{}
}
func (b *NormalBuilder) setWindowType() {
b.windowType = "Wooden Window"
}
func (b *NormalBuilder) setDoorType() {
b.doorType = "Wooden Door"
}
func (b *NormalBuilder) setNumFloor() {
b.floor = 2
}
func (b *NormalBuilder) getHouse() House {
return House{
doorType: b.doorType,
windowType: b.windowType,
floor: b.floor,
}
}
iglooBuilder.go: 具象ビルダー
package main
type IglooBuilder struct {
windowType string
doorType string
floor int
}
func newIglooBuilder() *IglooBuilder {
return &IglooBuilder{}
}
func (b *IglooBuilder) setWindowType() {
b.windowType = "Snow Window"
}
func (b *IglooBuilder) setDoorType() {
b.doorType = "Snow Door"
}
func (b *IglooBuilder) setNumFloor() {
b.floor = 1
}
func (b *IglooBuilder) getHouse() House {
return House{
doorType: b.doorType,
windowType: b.windowType,
floor: b.floor,
}
}
house.go: 製品
package main
type House struct {
windowType string
doorType string
floor int
}
director.go: ディレクター
package main
type Director struct {
builder IBuilder
}
func newDirector(b IBuilder) *Director {
return &Director{
builder: b,
}
}
func (d *Director) setBuilder(b IBuilder) {
d.builder = b
}
func (d *Director) buildHouse() House {
d.builder.setDoorType()
d.builder.setWindowType()
d.builder.setNumFloor()
return d.builder.getHouse()
}
main.go: クライアント・コード
package main
import "fmt"
func main() {
normalBuilder := getBuilder("normal")
iglooBuilder := getBuilder("igloo")
director := newDirector(normalBuilder)
normalHouse := director.buildHouse()
fmt.Printf("Normal House Door Type: %s\n", normalHouse.doorType)
fmt.Printf("Normal House Window Type: %s\n", normalHouse.windowType)
fmt.Printf("Normal House Num Floor: %d\n", normalHouse.floor)
director.setBuilder(iglooBuilder)
iglooHouse := director.buildHouse()
fmt.Printf("\nIgloo House Door Type: %s\n", iglooHouse.doorType)
fmt.Printf("Igloo House Window Type: %s\n", iglooHouse.windowType)
fmt.Printf("Igloo House Num Floor: %d\n", iglooHouse.floor)
}
output.txt: 実行結果
Normal House Door Type: Wooden Door
Normal House Window Type: Wooden Window
Normal House Num Floor: 2
Igloo House Door Type: Snow Door
Igloo House Window Type: Snow Window
Igloo House Num Floor: 1