Builder

  • 同じ生成手順で異なる材料を使って異なるオブジェクトを生成するパターン
    • 「建築者」が利用者に渡された材料を使って、一連の手順に沿ってオブジェクトを生成する
      • 家を建てるのと同じ
        • 枠組みを作って、ドアをつけて、屋根をつけて、窓をつける…
        • これらの手順は複数の家で同じものの材料が異なる
  • 「継承」「ポリモーフィズム」「移譲」を利用したパターン
    • BuilderConcreteBuilderが継承(実装)関係
    • DirectorBuilderのAPIを使って様々なConcreteBuilderを操作することができる
    • DirectorBuilderのメソッドを呼び出して処理を移譲する

メリット・デメリット

メリット

  • 生成されるオブジェクトの生成過程や生成手段を隠すことができる
  • オブジェクト構築用のコードをビジネスロジックから分離することができる

デメリット

  • 複数のクラスを作成する必要があり、過剰な設計となる可能性がある

用途

  • 生成手順が同じで、詳細が異なるオブジェクトを生成する場合
  • 大量のパラメータをコンストラクタに渡してオブジェクトを生成している場合
    • Builderの各工程で必要な値のみを渡すことで、パラメータを小分けにして渡すことができる
    • 可読性の向上とバグの可能性を低減させる

デザインパターンの種類

生成に関するデザインパターン

例(Mermaid)

  • Builder
    • インターフェースもしくは抽象クラス
    • オブジェクトの「生成手段」となるAPIを提供する
  • ConcreteBuilder
    • Builderで提供されるAPIを実装するクラス
    • 生成したオブジェクトを取得するためのメソッドも提供する
  • Director
    • 「建築者」の役割を持つクラス
    • Builderクラスで定義されたAPIを使ってオブジェクトを生成する
classDiagram
	class Client{
	}
	class Director{
		builder
		construct()
	}
	class Builder{
		<<interface>>
		buildPart1()
		buildPart2()
		buildPart3()
	}
	class ConcreteBuilder{
		buildPart1()
		buildPart2()
		buildPart3()
		getResult()
	}
	class Product{
	}
	Client --> Director
	Client --> ConcreteBuilder
	Director o--> Builder 
	ConcreteBuilder ..|> Builder
	ConcreteBuilder --> Product

構成要素

sequenceDiagram
	participant Client
	participant Director
	participant ConcreteBuilder
    Client ->> ConcreteBuilder: new
	Client ->> +Director: construct
    Director ->> +ConcreteBuilder: buildPart1
    ConcreteBuilder -->> -Director: 
    Director ->> +ConcreteBuilder: buildPart2
    ConcreteBuilder -->> -Director: 
    Director ->> +ConcreteBuilder: buildPart3
    ConcreteBuilder -->> -Director: 
    Director ->> -Client: 
    Client ->> ConcreteBuilder: getResult
classDiagram
	DesktopBuilder <-- Client
	LaptopBuilder <-- Client
	Computer <-- DesktopBuilder 
	Computer <-- LaptopBuilder 
	ComputerBuilder <.. DesktopBuilder :implements 
	ComputerBuilder <.. LaptopBuilder :implements 
	
	class Computer {
		type: string 
		cpu: string 
		ram: number
	}
	
	class ComputerBuilder {
		<<interface>>
		-computer Computer
		addCpu(cpu)
		addRam(ram)
	}
	
	class DesktopBuilder {
		-computer Computer
		addCpu(cpu)
		addRam(ram)
		getResult() Computer
	}
	class LaptopBuilder {
		-computer Computer
		addCpu(cpu)
		addRam(ram)
		getResult() Computer
	}
	class Client {
		
	}
	class Director{
		builder ComputerBuilder 
		construct()
		highSpecConstruct()
	}
	Client --> Director
	Director o--> ComputerBuilder