ビルダーパターンは、オブジェクト指向プログラミングにおけるさまざまなオブジェクト生成の問題に対する柔軟な解決策を提供するデザインパターンです。ビルダーパターンは、複雑なオブジェクトの構築をその表現から分離します。これは、書籍「デザインパターン」で説明されている23の古典的なデザインパターンの1つであり、生成パターンとしてサブカテゴリ化されています。[ 1 ]
ビルダーデザインパターンは、次のような問題を解決します。[ 2 ]
複雑なオブジェクトの構成要素をクラス内で直接作成・組み立てる方法は柔軟性に欠けます。クラスは特定の表現方法に縛られてしまい、後からクラス自体を変更せずに表現方法を変更することが不可能になります。通常、これはメソッドチェーンと流暢なAPIによって実現されます。
ビルダーデザインパターンは、このような問題を解決する方法を説明しています。
Builderオブジェクトにカプセル化する。Builderオブジェクトを直接作成するのではなく、オブジェクトの作成を別のオブジェクトに委任します。クラス(同じ構築プロセス)は、異なるBuilderオブジェクトに処理を委譲することで、複雑なオブジェクトの異なる表現を作成することができる。
ビルダーデザインパターンの目的は、複雑なオブジェクトの構築とその表現を分離することです。そうすることで、同じ構築プロセスで異なる表現を作成できます。[ 1 ]
ビルダーパターンの利点には次のものがあります: [ 3 ]
ビルダーパターンの欠点としては、以下のようなものがある。

上記のUMLクラス図では、クラスはオブジェクトとオブジェクトを直接Director作成および組み立てません。代わりに、は複雑なオブジェクトのパーツを構築 (作成および組み立て) するためのインターフェースを参照し、これによりはどの具象クラスがインスタンス化されるか (どの表現が作成されるか) に依存しなくなります。クラスは、オブジェクトとオブジェクトを作成および組み立てることで、このインターフェースを実装します。UML シーケンス図は 、実行時の相互作用を示しています。オブジェクトはオブジェクトを呼び出し、オブジェクトはオブジェクトを作成および組み立てます。その後、はを呼び出し、オブジェクトはオブジェクトを作成および組み立てます。ProductA1ProductB1DirectorBuilderDirectorBuilder1BuilderProductA1ProductB1DirectorbuildPartA()Builder1ProductA1DirectorbuildPartB()Builder1ProductB1

Builderオブジェクト(製品)を作成するための抽象的なインターフェース。ConcreteBuilder: の実装を提供します。ファクトリーBuilderとして、オブジェクトを構築するためのパーツを構築および組み立てます。このC++ の例では、クラスは流暢な APIを介して構築するために使用されるComputer内部クラスを持ち、コンストラクタをプライベートにして、メソッドがオブジェクトへのスマートポインタを返すようにしています。BuilderComputerbuild()Computer
import std ;using std :: string ; using std :: unique_ptr ;class Computer { private : string cpu ; string gpu ; int ram ; // デフォルト値int storage ; // デフォルト値Computer ( string cpu , string gpu , int ram , int storage ) : cpu { std :: move ( cpu )}, gpu { std :: move ( gpu )}, ram { ram }, storage { storage } {} public : ~ Computer () = default ;void showSpecs () { std :: println ( "コンピュータのスペック:" ); std :: println ( "CPU: {}" , cpu ); std :: println ( "GPU: {}" , gpu ); std :: println ( "RAM: {} GB" , ram ); std :: println ( "ストレージ: {} GB" , storage ); }class Builder { private : // Builder にはデフォルトのパラメータが与えられますstring cpu = "Generic CPU" ; string gpu = "Integrated Graphics" ; int ram = 16 ; int storage = 512 ; public : Builder () = default ;Builder & ofCpu ( string cpu ) noexcept { this -> cpu = std :: move ( cpu ); return * this ; }Builder & ofGpu ( string gpu ) noexcept { this -> gpu = std :: move ( gpu ); return * this ; }Builder & withRam ( int gb ) noexcept { ram = gb ; return * this ; }Builder & withStorage ( int gb ) noexcept { storage = gb ; return * this ; }unique_ptr < Computer > build () { return unique_ptr < Computer > ( new Computer ( cpu , gpu , ram , storage )); } } ; };int main () { unique_ptr < Computer > myComputer = Computer :: Builder () . ofCpu ( "AMD Ryzen 7" ) . ofGpu ( "NVIDIA RTX 4070" ) . withRam ( 32 ) . withStorage ( 1000 ) . build ();myComputer- > showSpecs (); }このC# の例では、上記の例でインスタンスDirectorを組み立て、構築を、によってに渡された別のビルダー オブジェクトに委任します。BicycleDirectorClient
名前空間Wikipedia.Examples ;public class Bicycle { // プロパティは不変性を保つために初期化専用または読み取り専用に設定されますpublic string Make { get ; init ; } public string Model { get ; init ; } public int Height { get ; init ; } public string Color { get ; init ; }public Bicycle ( string make , string model , string color , int height ) { Make = make ; Model = model ; Color = color ; Height = height ; } }/// <summary> /// 標準的な流暢なメソッドを使用した、正しいビルダー抽象化。/// </summary> public interface IBicycleBuilder { IBicycleBuilder SetColour ( string color ); IBicycleBuilder SetHeight ( int height ); Bicycle Build (); }/// <summary> /// 具体的なビルダーは、自身の状態を安全にカプセル化します。/// </summary> public class GTBuilder : IBicycleBuilder { private string _colour = "Black" ; // デフォルト値private int _height = 26 ; // デフォルト値public IBicycleBuilder SetColor ( string color ) { _color = color ; return this ; // メソッドチェーンのために自身を返す}public IBicycleBuilder SetHeight ( int height ) { _height = height ; return this ; }public Bicycle Build () { // 必要に応じてインスタンス化前にここで検証が行われますreturn new Bicycle ( "GT" , "Avalanche" , _color , _height ); } }/// <summary> /// Director は、ビルダーの流暢なインターフェースを使用してシーケンスを制御します。/// </summary> public class MountainBikeBuildDirector { private readonly IBicycleBuilder _builder ;public MountainBikeBuildDirector ( IBicycleBuilder builder ) { _builder = builder ; }public Bicycle Construct () { // Director がステップをスムーズに調整しますreturn _builder . SetColor ( "Red" ) . SetHeight ( 29 ) . Build (); } }Java はビルダーパターンを多用しています。例えば、java.lang.StringBuilderクラスは を構築するために使用されますjava.lang.String。[ 5 ]
StringBuilder sb = new StringBuilder () .append ( "Hello" ) .append ( ","" ) .append ( " world" ) .append ( " !" ) .insert ( 0 , " [INFO] " ) ;String message = sb.toString (); System.out.println ( message ); // "[INFO] Hello, world! "と出力されます同様に、このクラスjava.util.Localeには内部Builderクラスがあり、セッターメソッドを使用して構築するため、コンストラクタやof()ファクトリメソッドは使用されません。[ 6 ]
import java.util.Locale ;Locale frenchCanadian = new Locale.Builder () .setLanguage ( "fr" ) //言語をフランス語に設定.setRegion ( "CA" ) // 地域をカナダに設定.setVariant ( "POLY" ) //カスタムバリアントを設定.build ( ); // Localeを構築// " French (Canada,POLY)" と出力されますSystem.out.println ( frenchCanadian.getDisplayName ( ) ) ; // " fr -CA-x-lvariant-POLY" と出力されますSystem.out.println ( frenchCanadian.toLanguageTag ( ) ) ;Javaストリーム()には、オブジェクトを作成するために使用されるjava.util.stream内部Builder<T>インターフェースjava.util.stream.Stream<E>があります。[ 7 ]
さらに、やのようなクラスはjava.net.http.HttpClientすべてjava.net.http.HttpRequest内部にネストされたBuilderクラスを持っています。[ 8 ] [ 9 ]
Rustでは、ビルダーパターンによって API にオプションのパラメータを持たせることができます。これは、Rust がデフォルトパラメータや関数オーバーロードを許可していないためです。
#[derive(Debug)] pub struct Server { host : String , port : u16 , }impl Server { pub fn builder () -> ServerBuilder { ServerBuilder :: default () } }#[derive(Default)] pub struct ServerBuilder { host : Option < String > , port : Option < u16 > , }impl ServerBuilder { pub fn host ( mut self , host : & str ) -> Self { self . host = Some ( host . to_string ()); self }pub fn port ( mut self , port : u16 ) -> Self { self . port = Some ( port ); self }pub fn build ( self ) -> Result < Server , &' static str > { let host = self . host . ok_or ( "ホストは必須です" ) ? ; let port = self . port . unwrap_or ( 8080 );OK (サーバー{ホスト、ポート}) } }fn main () { let server = Server :: builder ( ) .host ( " 127.0.0.1" ) .port ( 3000 ) .build (); println ! ( "{:?}" , server ); }C++とは異なり、Rustでは型を別の型の中にネストすることはできませんが( のようにServer::Builder)、代わりにを作成するServerメソッドがあり、そのメソッドは最終的にインスタンスを返します。builder()ServerBuilderbuild()Server