Builderパターンとは
Builderパターンは、GoF(Gang of Four)によって定義されたデザインパターンの一つで、オブジェクトの生成プロセスを抽象化することによって、柔軟で動的なオブジェクトの生成を可能にするものです。このパターンは、特に複雑な構造を持つオブジェクトを生成する際に、そのプロセスを明確にし、クライアントコードの可読性を向上させる効果があります。
Builderパターンの構成要素
Builderパターンは主に以下の要素で構成されています。
1.
Builder (ビルダー): オブジェクトの各部分を構築するインターフェースを定義します。具体的な構築処理は、サブクラスで実装されます。
2.
Concrete Builder (具体的なビルダー): Builderインターフェースを実装し、具体的なオブジェクトの生成プロセスを定義します。このクラスが、実際にオブジェクトをどのように構築するかを決定します。
3.
Director (ディレクター): オブジェクトの構築プロセスを管理し、Builderのメソッドを呼び出してオブジェクトを構築します。Directorは、どのConcrete Builderを使用するかを決定します。
4.
Product (生成物): 構築されるオブジェクトそのものです。複数の異なるオブジェクトが生成される可能性があります。
Builderパターンのクラス図
Builderパターンの
クラス図は、上記のような構成要素間の関係を明確に示します。通常、Builderはインターフェースまたは抽象クラスとして定義され、Concrete Builderはそれらを実装します。DirectorはBuilderインターフェースに依存し、具体的なBuilderには依存しないことで、柔軟性が確保されます。
Builderパターンの利用例 (Java)
以下に
Javaでの具体的な利用例を示します。
java
// Product: 生成物
class Building {
private String foundation;
private String wall;
private String roof;
public void setFoundation(String foundation) {
this.foundation = foundation;
}
public void setWall(String wall) {
this.wall = wall;
}
public void setRoof(String roof) {
this.roof = roof;
}
public void display() {
System.out.println("Foundation: " + foundation);
System.out.println("Wall: " + wall);
System.out.println("Roof: " + roof);
}
}
// Builder: 構築インターフェース
interface BuildingBuilder {
void buildFoundation();
void buildWall();
void buildRoof();
Building getBuilding();
}
// ConcreteBuilder: 具体的な構築クラス
class WoodenHouseBuilder implements BuildingBuilder {
private Building building = new Building();
@Override
public void buildFoundation() {
building.setFoundation("Wooden Foundation");
}
@Override
public void buildWall() {
building.setWall("Wooden Wall");
}
@Override
public void buildRoof() {
building.setRoof("Wooden Roof");
}
@Override
public Building getBuilding() {
return building;
}
}
class StoneHouseBuilder implements BuildingBuilder {
private Building building = new Building();
@Override
public void buildFoundation() {
building.setFoundation("Stone Foundation");
}
@Override
public void buildWall() {
building.setWall("Stone Wall");
}
@Override
public void buildRoof() {
building.setRoof("Stone Roof");
}
@Override
public Building getBuilding() {
return building;
}
}
// Director: 構築管理クラス
class Director {
private BuildingBuilder builder;
public Director(BuildingBuilder builder) {
this.builder = builder;
}
public Building construct() {
builder.buildFoundation();
builder.buildWall();
builder.buildRoof();
return builder.getBuilding();
}
}
public class Main {
public static void main(String[] args) {
Director director1 = new Director(new WoodenHouseBuilder());
Building woodenHouse = director1.construct();
woodenHouse.display();
Director director2 = new Director(new StoneHouseBuilder());
Building stoneHouse = director2.construct();
stoneHouse.display();
}
}
このコードでは、`Building`クラスが生成物、`BuildingBuilder`インターフェースがBuilder、`WoodenHouseBuilder`と`StoneHouseBuilder`がConcrete Builder、`Director`がDirectorの役割を担っています。
このコードの実行結果は以下の通りです。
Foundation: Wooden Foundation
Wall: Wooden Wall
Roof: Wooden Roof
Foundation: Stone Foundation
Wall: Stone Wall
Roof: Stone Roof
この例から、Directorの管理下で、異なるBuilderが異なるBuildingインスタンスを生成していることが分かります。
Builderパターンと関連するパターン
1.
Strategyパターン: BuilderをStrategyパターンにおけるContextとして設計することで、インスタンスの生成プロセスをより柔軟にすることができます。BuilderのインターフェースをStrategyインターフェースとして扱い、異なるConcrete BuilderをStrategyとして切り替えることで、生成方法を動的に変更できます。
2.
Compositeパターン: Compositeパターンで示されるような複雑な構造を持つインスタンスは、Builderパターンを応用することで効率的に生成できます。例えば、Compositeの各要素をBuilderで段階的に構築することで、複雑な構造でも容易に生成することができます。
まとめ
Builderパターンは、オブジェクトの生成プロセスを明確にし、柔軟性と可読性を向上させる強力なデザインパターンです。特に、複雑なオブジェクトや、生成プロセスに複数のステップが必要な場合に有効です。GoFのデザインパターンの中でも汎用性が高く、多くのソフトウェア開発現場で活用されています。