Builderパターンとは?
Builderパターンは、複雑なオブジェクトを段階的に組み立てるための設計パターンです。
例えば、パソコンを組み立てるとき。CPU選んで、メモリ決めて、ストレージ付けて...という感じで、1つずつパーツを組み合わせていきますよね?Builderパターンは、このプロセスをコードで実現するためのパターンなんです。
登場人物

(wikiより抜粋)
- Product(生成物): 作りたいオブジェクト本体
- Builder(ビルダー): オブジェクトの組み立て方を定義するインターフェース
- ConcreteBuilder(具象ビルダー): 実際に組み立てを行うクラス
- Director(監督): 組み立ての手順を管理する人(オプション)
メリット
Builderパターンを使うメリットは以下の通りです。
1. 複雑なオブジェクト作りがわかりやすくなる
オブジェクトを作る作業を小さいステップに分けられるので、何をやってるのか分かりやすいです。
2. コンストラクタ地獄から解放される
引数がたくさんあるコンストラクタって、見るだけで避けたくなりますよね... Builderパターンなら、メソッドチェーンで分かりやすく書けます。
// コンストラクタ地獄の例
var pc = new Computer("Intel i9", "32GB", "1TB", "RTX 4080", true, true);
// Builderパターンを使った例
var pc = new ComputerBuilder()
.SetCPU("Intel i9")
.SetRAM("32GB")
.SetStorage("1TB")
.SetGPU("RTX 4080")
.AddWiFi()
.AddBluetooth()
.Build();
3. 同じ手順で違うものが作れる
Directorで組み立て手順を決めておけば、パーツを変えるだけで色んなバリエーションが作れます。料理のレシピみたいな感じですね☝️
4. 中途半端なオブジェクトができない
Build()を呼ぶまではオブジェクトが完成しないので、「あれ、これ設定し忘れてた!」みたいなミスを防げます。
5. コードが読みやすくなる
何をやってるのか一目瞭然なので、後から見返した時や、他の人がコードを読む時に助かります。機能追加も楽ちんです。
実装してみる
早速実装してみましょう! パソコンを組み立てる例で試してみます。
using System;
// 構築する製品クラス(Product)
public class Computer
{
public string CPU { get; set; }
public string RAM { get; set; }
public string Storage { get; set; }
public string GPU { get; set; }
public bool HasWiFi { get; set; }
public bool HasBluetooth { get; set; }
public override string ToString()
{
return $"Computer: CPU={CPU}, RAM={RAM}, Storage={Storage}, " +
$"GPU={GPU}, WiFi={HasWiFi}, Bluetooth={HasBluetooth}";
}
}
// Builderインターフェース
public interface IComputerBuilder
{
IComputerBuilder SetCPU(string cpu);
IComputerBuilder SetRAM(string ram);
IComputerBuilder SetStorage(string storage);
IComputerBuilder SetGPU(string gpu);
IComputerBuilder AddWiFi();
IComputerBuilder AddBluetooth();
Computer Build();
}
// 具象Builderクラス(ConcreteBuilder)
public class ComputerBuilder : IComputerBuilder
{
private Computer _computer = new Computer();
public IComputerBuilder SetCPU(string cpu)
{
_computer.CPU = cpu;
return this;
}
public IComputerBuilder SetRAM(string ram)
{
_computer.RAM = ram;
return this;
}
public IComputerBuilder SetStorage(string storage)
{
_computer.Storage = storage;
return this;
}
public IComputerBuilder SetGPU(string gpu)
{
_computer.GPU = gpu;
return this;
}
public IComputerBuilder AddWiFi()
{
_computer.HasWiFi = true;
return this;
}
public IComputerBuilder AddBluetooth()
{
_computer.HasBluetooth = true;
return this;
}
public Computer Build()
{
return _computer;
}
}
// Director(あらかじめ作成手順を決めておける)
public class ComputerDirector
{
private IComputerBuilder _builder;
public ComputerDirector(IComputerBuilder builder)
{
_builder = builder;
}
// ゲーミングPC構成
public Computer ConstructGamingPC()
{
return _builder
.SetCPU("Intel Core i9")
.SetRAM("32GB")
.SetStorage("1TB SSD")
.SetGPU("NVIDIA RTX 4080")
.AddWiFi()
.AddBluetooth()
.Build();
}
// オフィスPC構成
public Computer ConstructOfficePC()
{
return _builder
.SetCPU("Intel Core i5")
.SetRAM("16GB")
.SetStorage("512GB SSD")
.AddWiFi()
.Build();
}
}
// 使用例
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== Builderを直接使用 ===");
// ゲーミングPC
var gamingPC = new ComputerBuilder()
.SetCPU("Intel Core i9")
.SetRAM("32GB")
.SetStorage("1TB SSD")
.SetGPU("NVIDIA RTX 4080")
.AddWiFi()
.AddBluetooth()
.Build();
Console.WriteLine(gamingPC);
// オフィス用PC
var officePC = new ComputerBuilder()
.SetCPU("Intel Core i5")
.SetRAM("16GB")
.SetStorage("512GB SSD")
.AddWiFi()
.Build();
Console.WriteLine(officePC);
Console.WriteLine("\n=== Directorを使用 ===");
// Directorを使った構築
var director = new ComputerDirector(new ComputerBuilder());
var gamingPC2 = director.ConstructGamingPC();
var officePC2 = director.ConstructOfficePC();
Console.WriteLine(gamingPC2);
Console.WriteLine(officePC2);
}
}
実行結果
=== Builderを直接使用 ===
Computer: CPU=Intel Core i9, RAM=32GB, Storage=1TB SSD, GPU=NVIDIA RTX 4080, WiFi=True, Bluetooth=True
Computer: CPU=Intel Core i5, RAM=16GB, Storage=512GB SSD, GPU=, WiFi=True, Bluetooth=False
=== Directorを使用 ===
Computer: CPU=Intel Core i9, RAM=32GB, Storage=1TB SSD, GPU=NVIDIA RTX 4080, WiFi=True, Bluetooth=True
Computer: CPU=Intel Core i5, RAM=16GB, Storage=512GB SSD, GPU=, WiFi=True, Bluetooth=False
まとめ
Builderパターンは、複雑なオブジェクトを作る時にすごく便利なデザインパターンです。コードの可読性と保守性のUPも見込めます!
こんな時にBuilderパターンの利用を検討してみてください💡
- コンストラクタの引数が多すぎる(4つ以上が目安)
- オブジェクトを作る手順がややこしい
- 同じ作り方で色んなバリエーションを作りたい
- オプション的なパラメータがたくさんある