BuilderのデザインパターンとFactoryのデザインパターンの違いは何ですか?
どちらが有利なのか、またその理由は何ですか。
これらのパターンをテストして比較/対比したい場合、どのようにして自分の調査結果をグラフとして表すのですか?
デザインパターンでは、通常すべての場合に有効な「より有利な」ソリューションはありません。実装する必要があるものによって異なります。
ウィキペディアより
- Builderは、複雑なオブジェクトを段階的に作成することに焦点を当てています。 Abstract Factoryは、製品オブジェクトのファミリー(単純または複雑)を強調しています。 Builderは最終ステップとして製品を戻しますが、抽象ファクトリーに関する限り、製品は即時に戻されます。
- Builderはしばしばコンポジットを構築します。
- 多くの場合、設計はファクトリメソッドを使用して開始し(複雑さが少なく、カスタマイズが容易で、サブクラスが増える)、設計者がより柔軟性が必要な場所を見つけ出すにつれて、抽象ファクトリ、プロトタイプ、またはビルダー(より柔軟で複雑)に進化します。
- 創造的なパターンが補完的な場合もあります。Builderは他のパターンのいずれかを使用して、どのコンポーネントを構築するかを実装できます。 Abstract Factory、Builder、およびPrototypeは、その実装にSingletonを使用できます。
工場設計パターンに関するWikipediaのエントリ: http://ja.wikipedia.org/wiki/Factory_method_pattern
ビルダーデザインパターンのウィキペディアのエントリ: http://ja.wikipedia.org/wiki/Builder_pattern
ファクトリは単にコンストラクタ(おそらく別のクラスにあるもの)を囲むラッパー関数です。主な違いは、ファクトリメソッドパターンでは、すべてのパラメータが1行で渡されるため、オブジェクト全体を1つのメソッド呼び出しで構築する必要があるということです。最後のオブジェクトが返されます。
一方、ビルダーパターンは、本質的には、コンストラクタ呼び出しに渡す可能性があるすべての可能なパラメータを囲むラッパーオブジェクトです。これにより、設定メソッドを使ってパラメータリストをゆっくり構築することができます。ビルダークラスのもう1つのメソッドはbuild()メソッドです。これは単にビルダーオブジェクトを目的のコンストラクターに渡し、結果を返します。
Javaのような静的言語では、可能性のあるすべてのパラメーターの組み合わせに対して伸縮コンストラクターを用意する必要がなくなるため、少数の(潜在的にオプションの)パラメーターがある場合、これはより重要になります。また、ビルダーを使用すると、設定メソッドを使用して、コンストラクターが呼び出された後で直接変更できない読み取り専用またはプライベートフィールドを定義できます。
基本的な工場例
// Factory
static class FruitFactory {
static Fruit create(name, color, firmness) {
// Additional logic
return new Fruit(name, color, firmness);
}
}
// Usage
Fruit fruit = FruitFactory.create("Apple", "red", "crunchy");
基本ビルダーの例
// Builder
class FruitBuilder {
String name, color, firmness;
FruitBuilder setName(name) { this.name = name; return this; }
FruitBuilder setColor(color) { this.color = color; return this; }
FruitBuilder setFirmness(firmness) { this.firmness = firmness; return this; }
Fruit build() {
return new Fruit(this); // Pass in the builder
}
}
// Usage
Fruit fruit = new FruitBuilder()
.setName("Apple")
.setColor("red")
.setFirmness("crunchy")
.build();
これら2つのウィキペディアのページからのコードサンプルを比較する価値があるかもしれません:
http://ja.wikipedia.org/wiki/Factory_method_pattern
http://ja.wikipedia.org/wiki/Builder_pattern
Factoryパターンは、ほぼBuilderパターンの単純化されたバージョンと見なすことができます。
Factoryパターンでは、ファクトリがニーズに応じてオブジェクトのさまざまなサブタイプを作成します。
ファクトリメソッドのユーザーは、そのオブジェクトの正確なサブタイプを知る必要はありません。ファクトリメソッドcreateCar
の例は、Ford
またはHonda
型付きオブジェクトを返すかもしれません。
Builderパターンでは、異なるサブタイプもBuilderメソッドによって作成されますが、オブジェクトの構成は同じサブクラス内で異なる場合があります。
自動車の例を続けるには、4気筒エンジンでcreateCar
型のオブジェクト、または6気筒でHonda
型のオブジェクトを作成するHonda
ビルダーメソッドがあります。ビルダーパターンにより、この細かい粒度が可能になります。
ビルダーパターン と ファクトリメソッドパターン の両方の図が利用可能です。ウィキペディア.
ビルダー設計パターンは、いくつかのステップにわたって特定のタイプの別のオブジェクトを作成する方法を知っているオブジェクトを表します。各中間ステップでターゲットアイテムに必要な状態を保持します。 StringBuilderが最終的な文字列を生成するために通過するものを考えてください。
ファクトリデザインパターンは、与えられたパラメータに基づいて特定のタイプが選択される、1ステップでいくつかの異なるが関連した種類のオブジェクトを作成する方法を知っているオブジェクトを記述します。シリアライザーを作成し、それが1回のロード呼び出しで目的のオブジェクトをすべて構成する、シリアライゼーションシステムを考えてみましょう。
ステップバイステップで複雑なオブジェクトを構築する:ビルダーパターン
単純なオブジェクトは、単一のメソッドを使用して作成されます。ファクトリメソッドパターン
複数ファクトリメソッドを使用したオブジェクトの作成:抽象ファクトリパターン
どちらもオブジェクトを作成するための作成パターンです。
1)Factory Pattern - スーパークラスが1つとサブクラスがN個あるとします。オブジェクトはどのパラメータ/値が渡されるかによって作成されます。
2)ビルダーパターン - 複雑なオブジェクトを作成します。
Ex: Make a Loan Object. Loan could be house loan, car loan ,
education loan ..etc. Each loan will have different interest rate, amount ,
duration ...etc. Finally a complex object created through step by step process.
ビルダーパターンとファクトリーパターンは、どちらもあなたのためにオブジェクトを作成するので、どちらも裸眼にかなり似ているように見えます。
この実例は、両者の違いをより明確にします。
あなたがファーストフードのレストランに行き、あなたがFoodを注文したとします。
ピザ
トウガラシ、トマト、バーベキューチキン、NOパイナップル
そのため、ファクトリーパターンによってさまざまな種類の食品が製造されますが、特定の食品のさまざまな変種(フレーバー)はビルダーパターンによって製造されます。
食品の種類
ピザ、ハンバーガー、パスタ
ピザの変種
チーズのみ、チーズ+トマト+トウガラシ、チーズ+トマトなど.
ここで両方のパターンのサンプルコードの実装を見ることができます。
ビルダーパターン
工場出荷時のパターン
私の主張に従うべき最初の一般的な事柄:
大規模なソフトウェアシステムを設計する際の主な課題は、柔軟で変更が容易でないことです。このため、カップリングや凝集など、いくつかの測定基準があります。システム全体を最初から再設計する必要なく、機能を簡単に変更または拡張できるシステムを実現するには、設計原則(SOLIDなど)に従うことができます。しばらくして、開発者の中には、それらがそれらの原則に従うならば、同様の問題に対してうまくいくいくつかの同様の解決策があることを認識しました。これらの標準的な解決策がデザインパターンであることがわかりました。
そのため、デザインパターンは、疎結合で高い凝集力を持つシステムを実現するために、一般的なデザイン原則に従うことをサポートするものです。
質問に答える:
2つのパターンの違いを尋ねることによって、どのパターンがあなたのシステムをより柔軟にするのかを自問しなければなりません。各パターンには、システム内のクラス間の依存関係を整理するという独自の目的があります。
抽象ファクトリパターン:GoF:「具象クラスを指定せずに、関連または従属オブジェクトのファミリを作成するためのインタフェースを提供する」
これはどういう意味ですか?このようなインタフェースを提供することで、各ファミリの製品のコンストラクタへの呼び出しはファクトリクラスにカプセル化されます。そしてこれがあなたのシステム全体の中でこれらのコンストラクタが呼ばれる唯一の場所なので、新しいファクトリクラスを実装することであなたのシステムを変更することができます。別のものを通して工場の表現を交換するならば、あなたはあなたのコードの大部分に触れることなく製品の全体のセットを交換することができます。
ビルダーパターン:GoF:「同じ構築プロセスで異なる表現を作成できるように、複雑なオブジェクトの構築とその表現を分離する」
これはどういう意味ですか?あなたはディレクター(GoF)と呼ばれる別のクラスに構築のプロセスをカプセル化します。このディレクターは、製品の新しいインスタンスを作成するアルゴリズムを含みます(例えば、他の部分から複雑な製品を構成する)。製品全体の不可欠な部分を作成するために、ディレクターはビルダーを使用します。ディレクターでビルダーを交換することで、同じアルゴリズムを使用して製品を作成することができますが、単一部品の表現(したがって製品の表現)を変更することができます。製品の表現でシステムを拡張または変更するために必要なことは、新しいビルダークラスを実装することだけです。
要約すると、Abstract Factory Patternの目的は、一緒に使用できるようにする一連の製品を交換することです。ビルダーパターンの目的は、製品を作成するという抽象アルゴリズムをカプセル化して、製品のさまざまな表現に再利用することです。
私の考えでは、抽象ファクトリーパターンはビルダーパターンの兄弟であるとは言えません。はい、どちらも創造的なパターンですが、パターンの主な目的はまったく異なります。
私が作ることができたビルダーとファクトリーの間の1つの顕著な違いは以下の通りです
車があるとします。
class Car
{
bool HasGPS;
bool IsCityCar;
bool IsSportsCar;
int Cylenders;
int Seats;
public:
void Car(bool hasGPs=false,bool IsCityCar=false,bool IsSportsCar=false, int Cylender=2, int Seats=4);
};
上記のインターフェースでは、次の方法で自動車に乗ることができます。
int main()
{
BadCar = new Car(false,false,true,4,4);
}
しかし、どうすれば、座席の作成中に何らかの例外が発生します。オブジェクトAT ALL //を取得できません
次のような実装があるとします。
class Car
{
bool mHasGPS;
bool mIsCityCar;
bool mIsSportsCar;
int mCylenders;
int mSeats;
public:
void Car() : mHasGPs(false), mIsCityCar(false), mIsSportsCar(false), mCylender(2), mSeats(4) {}
void SetGPS(bool hasGPs=false) {mHasGPs = hasGPs;}
void SetCity(bool CityCar) {mIsCityCar = CityCar;}
void SetSports(bool SportsCar) {mIsSportsCar = SportsCar;}
void SetCylender(int Cylender) {mCylenders = Cylender;}
void SetSeats(int seat) {mSeats = seat;}
};
class CarBuilder
{
Car* mCar;
public:
CarBuilder():mCar(NULL) { mCar* = new Car(); }
~CarBuilder() { if(mCar) { delete mCar; }
Car* GetCar() { return mCar; mCar=new Car(); }
CarBuilder* SetSeats(int n) { mCar->SetSeats(n); return this; }
CarBuilder* SetCylender(int n) { mCar->SetCylender(n); return this; }
CarBuilder* SetSports(bool val) { mCar->SetSports(val); return this; }
CarBuilder* SetCity(bool val) { mCar->SetCity(val); return this; }
CarBuilder* SetGPS(bool val) { mCar->SetGPS(val); return this; }
}
今、あなたはこのように作成することができます
int main()
{
CarBuilder* bp =new CarBuilder;
Car* NewCar = bp->SetSeats(4)->SetSports(4)->SetCity(ture)->SetGPS(false)->SetSports(true)->GetCar();
bp->SetSeats(2);
bp->SetSports(4);
bp->SetCity(ture);
bp->SetSports(true)
Car* Car_II= bp->GetCar();
}
ここでの2番目のケースでは、1つの操作が失敗したとしてもあなたはまだ車を手に入れるでしょう。
車が後で完全に動作しないということかもしれませんが、あなたはオブジェクトを持っているでしょう。
なぜなら、ファクトリーメソッドは、1回の呼び出しでCarを提供するのに対し、Builderは1つずつ構築するからです。
とはいえ、それはどちらを求めるべきかという意志の必要性次第です。
BuilderとAbstract Factoryは異なる目的のためのものです。正しいユースケースに応じて、適切なデザインパターンを選択する必要があります。
ビルダーの顕著な特徴
Factory(単純Factory)の顕著な特徴:
多くの場合、デザインはファクトリメソッドを使用して開始し(より複雑でカスタマイズ可能な、サブクラスが増殖する)、抽象ファクトリ、へと進化します、またはBuilder(より柔軟で複雑)
関連記事をご覧ください。
デザインパターン:Factory vs Factoryメソッドvs Abstract Factory
詳細については、以下の記事を参照してください。
+-------------------------------------------------------------------+---------------------------------------------------+
| Builder | Factory |
+-------------------------------------------------------------------+---------------------------------------------------+
| Return only single instance to handle complex object construction | Retrun various instances on multiple constructors |
| No interface required | Interface driven |
| Inner classes is involved (to avoid telescopic constructors) | Subclasses are involved |
+-------------------------------------------------------------------+---------------------------------------------------+
アナロジー:
Abstract Factory&Builderパターンはどちらも作成パターンですが、意図は異なります。
抽象ファクトリパターンは、関連オブジェクトのファミリに対してオブジェクトの作成を強調します。
ビルダーパターンは、複雑なオブジェクトを段階的に構築することに焦点を当てています。それは複雑なオブジェクトを構成するプロセスから表現を切り離すので、異なる表現に対して同じ構築プロセスを使用することができます。
複雑な構成は、構成されるべき対象が抽象によって表される他の異なる対象から構成される場合である。
マクドナルドのメニューを考えてみましょう。メニューにはドリンク、メイン、サイドがあります。個々の抽象化のどの子孫が一緒に構成されているかに応じて、作成されたメニューは別の表現を持ちます。
そこでは、表現が異なる2つのメニューのインスタンスを取得しました。順番に建設のプロセスは変わりません。あなたは飲み物、メインとサイドでメニューを作ります。
ビルダーパターンを使用することで、複雑なオブジェクトを作成するためのアルゴリズムと、それを作成するために使用されるさまざまなコンポーネントとを分離できます。
ビルダーパターンに関しては、アルゴリズムはディレクターにカプセル化されていますが、ビルダーは不可欠な部分を作成するために使用されます。他の部分はメニューに構成されているため、ディレクターのアルゴリズムで使用されているビルダーを変更すると、表現が異なります。メニューの作成方法は変わりません。
どちらも非常によく似ていますが、オブジェクト作成用のパラメータがいくつかあり、そのいくつかがデフォルト値でオプションである場合は、Builderパターンを使用してください。
それらの主な違いは、Builderパターン主にが複雑なオブジェクトの作成を段階的に説明することです。 Abstract Factoryパターンでは、objects-productsのファミリに重点が置かれています。 Builderは最終ステップで製品を返します。 Abstract Factoryパターンでは、製品はすぐに利用可能です。
例:Mazeを作成しているとしましょう
1。Abstract Factory:
Maze* MazeGame::CreateMaze (MazeFactory& factory) {
Maze* maze = factory.MakeMaze(); /// product is available at start!!
/* Call some methods on maze */
return maze;
}
2。ビルダー:
Maze* MazeGame::CreateMaze (MazeBuilder& builder) {
builder.buildMaze(); /// We don't have access to maze
/* Call some methods on builder */
return builder.GetMaze();
}
FactoryとBuilderのパターンの使用方法と違いは、同じコードベースで作業を進め、要件を変更したときに、特定の期間内に理解しやすくなります。
私の経験からすると、通常は、静的作成メソッドをいくつか含むFactoryパターンから始めます。オブジェクトの階層構造が複雑になるにつれて(あるいは型を追加するにつれて)、おそらくあなたのメソッドにもっと多くのパラメータを取り込むことになるでしょう。Factoryモジュールを再コンパイルする必要はないのは言うまでもありません。これらすべてが、作成者メソッドの複雑さを増し、読みやすさを低下させ、作成モジュールをより脆弱にします。
この点が遷移点になる可能性があります。 FactoryからBuilderへの移行パターン。そうすることで、構築パラメータの周りにラッパーモジュールを作成し、さらに抽象化を追加することによって(おそらく)新しいオブジェクトを表現することができます。 )実際の作成ロジックに触れることなく実装できます。それであなたはそれほど複雑でないロジックと再コンパイルされたソースコードを持っていました
率直に言って、私が直面するほとんどすべての場合に両方の方法を使用することができたので、唯一の多様性係数はそれらを区別するのに十分ではなかった。今は何の利益も経験せずに。これが私がついに考えたことです。
違いは明らかですビルダーパターンでは、ビルダーはあなたのためにオブジェクトの特定の種類を作成します。あなたはビルダーが何を構築しなければならないかを伝えなければなりません。ファクトリパターンでは、抽象クラスを使用して特定のオブジェクトを直接構築しています。
ここでビルダークラスはメインクラスと特定の型クラスの間の仲介者として機能します。より抽象的です。
Factory:オブジェクトの依存関係が完全にファクトリによって保持されているオブジェクトのインスタンスを作成するために使用されます。 抽象ファクトリパターンの場合、同じ抽象ファクトリの具体的な実装が多数あることがよくあります。ファクトリの正しい実装は依存性注入によって注入されます。
ビルダー:インスタンス化されるオブジェクトの依存関係が以下の場合、不変オブジェクトをビルドするために使用されます。一部は事前に認識されており、一部はビルダーのクライアントによって提供されています。
ビルドパターンは、オブジェクト作成の複雑さを強調しています( "steps"によって解決)
抽象パターンは、(複数だが関連している)オブジェクトの「抽象化」を「ただ」強調しています。
ビルダーと抽象ファクトリー
Builderのデザインパターンは、ある程度、Abstract Factoryパターンと非常によく似ています。それが、どちらか一方が使用されるときに状況間で違いを生むことができることが重要である理由です。抽象ファクトリの場合、クライアントはファクトリのメソッドを使用して独自のオブジェクトを作成します。 Builderの場合、Builderクラスはオブジェクトの作成方法を指示されてからそれを要求されますが、クラスをまとめる方法はBuilderクラスに依存します。この詳細は2つのパターンの違いを生み出します。
製品の共通インターフェース
実際には、コンクリートビルダーによって作成された製品は大幅に異なる構造を持っているので、異なる製品を共通の親クラスから派生させる理由がない場合はそうします。これはまた、Builderパターンと、共通タイプから派生したオブジェクトを作成するAbstract Factoryパターンとを区別します。
両方のパターンに同じ必要性があります。クライアントコードから複雑なオブジェクトの構築ロジックを隠します。しかし、何が「複雑な」(または、時に複雑になる)オブジェクトにするのでしょうか。主に、それは依存性、あるいはより部分的な状態から構成されるオブジェクトの状態によるものです。初期オブジェクトの状態を設定するためにコンストラクタによって依存関係を注入することができますが、オブジェクトにはそれらの多くを必要とするものもあります。そして、他のものはある条件によって動かされる状態に設定します。さらに、ある種の「忘却依存関係」であるオブジェクトプロパティもありますが、それらはオプションの状態をとることもできます。
その複雑さを支配する2つの有名な方法があります。
コンポジション/アグリゲーション:オブジェクトを構築し、その従属オブジェクトを構築し、そして一緒に配線します。ここで、ビルダーはコンポーネントの構築を導くルールを決定するプロセスを透明かつ柔軟にすることができます。
多態性:構築規則はサブタイプ定義に直接宣言されているため、各サブタイプごとに一連の規則があり、これらの規則のうちどれをオブジェクトの構築に適用するかを決定する条件があります。工場はこのシナリオに完全に適合します。
これら二つのアプローチを混ぜ合わせることを妨げるものは何もありません。製品ファミリーはビルダーでオブジェクトの作成を抽象化でき、ビルダーはファクトリーを使用してどのコンポーネントオブジェクトをインスタンス化するかを決定できます。
私見では
Builderはある種のより複雑なFactoryです。
しかし、Builderでは、他のファクトリを使用してオブジェクトをインスタンス化できます。これは、最終的で有効なオブジェクトを構築するために必要です。
それで、複雑さによる「創造的パターン」進化について話して、あなたはこのようにそれについて考えることができます:
Dependency Injection Container -> Service Locator -> Builder -> Factory
私の意見では、Builderパターンは他のオブジェクトの束からオブジェクトを作成したい時に使用され、部品の作成はあなたが作成したいオブジェクトから独立している必要がある時です。パーツの作成をクライアントから隠して、ビルダーとクライアントを独立させるのに役立ちます。複雑なオブジェクトの作成に使用されます(複雑なプロパティで構成されている可能性があるオブジェクト)。
ファクトリパターンは、あなたが共通のファミリーのオブジェクトを作成したいとあなたがそれをすぐに確認されることを望むことを指定する間。より単純なオブジェクトに使用されます。