春のセール
Builder

Builder を Go で

Builder は生成に関するデザインパターンの一つで 複雑なオブジェクトを段階的に構築することができます

他の生成に関するパターンとは異なり Builder ではプロダクト 訳注 本パターンでは 生成されるモノのことを一般にプロダクトと呼びます が共通のインターフェースを持つ必要はありません このため 同じ構築の手続きを経て 異なるプロダクトを作成することができます

概念的な例

Builder パターンは 目的とするプロダクトが複雑で 完成まで多くのステップが必要な時に使われます この場合 単一の超巨大なコンストラクターを持つよりも いくつかの構築メソッドを持つ方がシンプルです 多段階での構築方法では 未完成の 安全性に欠けるプロダクトがクライアントから利用可能になってしまうという潜在的問題がありますが Builder パターンを使うと 構築が完了するまで プロダクトは外部に非公開の状態が保たれます

以下のコードでは 異なる種類の家 igloonormal­House igloo­Buildernormal­Builder によって構築されています どちらの種類の家も 同じ構築ステップを使います ディレクター構造体は 構築過程を組織化する役に立ちます

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

他言語での Builder

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