2011-01-22 27 views
33

When would you use the Builder Pattern?から、ビルダー対Decoratorパターン

は、Builderパターンは、ピザ例えば適切であると言われています。

なぜデコレータですか? チーズ、ペパーロニ、ベーコンをベースピザの追加の装飾として扱うことにより、

チーズ/ペパロニを別に作る必要があるからですか?私は彼らがレディメイドで利用できるように別々に建てる必要があるとは思わない。

Plsを明確にする。 また、実際のデコレータパターンの現実的な例と、それがその特定の例に適している理由を探しています。ありがとうございました。

+0

は、私は私が例でこれを学んだと同じ考えを持っていました。教授は私を助けることができませんでしたが、これは、ありがとう! – Mene

答えて

36

:オブジェクト指向プログラミングで

、 Decoratorパターンは、新たな/追加の行動 を動的に既存のオブジェクト に追加することを可能にするデザインパターン です。

完成したピザにトッピングを追加する必要はありません。あなたは半分のピザを食べていないし、別のトッピングをそれに加えます。言い換えれば

Decoratorパターンを使用すると、施工時間後にオブジェクトに機能への拡張を追加することができますしながら、Builderパターンは、構築時に独立した方向に拡張可能であるオブジェクトを構築することが容易になります。オブジェクトを構築するためにデコレータパターンを使用するのは悪いです。なぜなら、setterを使用してオプションのコンストラクタ引数を指定するJavaBeanの問題と同様に、必要なデコレータがすべて配置されるまで、オブジェクトが一貫性のない状態(または少なくとも不正確な状態)

+1

potter:実際には、キッチンアップ、チリフレークなどのトッピングはピザと一緒に与えられます。では、両方のパターンを適用するといいですか?最初のビルダー、次にデコレータ? – bjskishore123

+0

potter:+1、上記の私の前提は正しいと思われるtoppings、http://stackoverflow.com/questions/2707401/please-help-me-understand-the-decorator-pattern-with-real-world-例 – bjskishore123

+3

@bjs:はい、デコレータとビルダーを分かりやすく組み合わせることができ、あなたの例は1つの可能性です。しかし、複雑な設計と読みにくいコードにつながります。ビルダー+デコレーターを使用するのは、私が実際にプロジェクトで必要とされていると確信していた場合だけで、 "パターンフィーバー"の場合は私の部分です。完全に吹き飛ばされた 'ChilliDecorator'を構築するのではなく、基本クラスに' addChilli() 'メソッドを追加するだけの価値があるかどうかを考えてみましょう。 (いつものように、正しい答えはありません) –

20

あなたは非常に異なる2つのことを混乱させています。 GoFはBuilderを作成パターンとして分類し、Decoratorは構造パターンとして分類します。彼らは、(ガンマら、ページ1)を次のように記載されている:

ビルダー(97)と同じ構成プロセスが異なる表現を作成できるように、その表現から複雑なオブジェクトの構造を分離します。

デコレータ(175)オブジェクトに追加の責任を動的に付けます。 デコレータは、機能を拡張するためにサブクラス化する柔軟な代替手段を提供します。

デコレータに重点​​を置いています。サブクラス化の柔軟な代替方法です。サブクラス化は、is-a関係をモデル化するために使用されます。チーズはピザではありません。ピザはであり、成分の数はであり、これは通常組成物を用いてモデル化される。

ビルダーパターンは、標準化された方法でそれらを構築するために必要な膨大な数の成分が存在するため、ここでは関連しています。

デコレータの実例を取るために、私は最近、Javaアプリケーションでjdbcを使って実行されたクエリを記録したかったのです。これを実現するには、Connectionインターフェイスを拡張したLoggingConnectionというクラスを実装します。

public class LoggingConnection implements Connection 
{ 
    public static class LogEntry 
    { 
     public String sql; 
     public int invocationCount; 
     public double avgTime; 
     public double maxTime; 
    } 

    private Connection delegate; 

    private Map<String, LogEntry> log; 

    public LoggingConnection(Connection delegate) 
    { 
     this.delegate = delegate; 
     this.log = new HashMap<String, LogEntry>(); 
    } 

    public Map<String, LogEntry> getLog() 
    { 
     return log; 
    } 

    @Override 
    public void clearWarnings() 
    throws SQLException 
    { 
     delegate.clearWarnings(); 
    } 

    @Override 
    public void close() 
    throws SQLException 
    { 
     delegate.close(); 
    } 

    // forwarding declarations to all other methods declared in the interface 
    ... 
} 

これにより、具体的な接続の実装をパスし、実行時にその機能を拡張することができます。実際に返される接続オブジェクトが必ずしもわからないので、このコンテキストではサブクラス化は問題になります。それはあなたがDriverManagerの工場を使用するために構築されていますので、これは次のとおりです。

Connection conn = DriverManger.getConnection(dsn); 

connオブジェクトは、このケースでは、私はgenerellyの名前を知らないドライバー、中に含まれる実装です。デコレータアプローチの利点は、私が知る必要はなく、特定の実装に結びついていないということです。ウィキペディアのDecoratorパターンの記事から

+1

まあ、「代替」は、サブクラス化も使用できることを示唆しています。サブクラス化の選択肢は、チーズをピザのサブクラスにするのではなく、むしろピザのチーズ_pizza_サブクラスを持つことです。チーズのピザはピザなので、 –

+0

@Lèse:しかし、サブクラスのように同じ「チーズ」機能を追加するデコレータを実装できると考えられます。唯一の大きな違いは、実行時に拡張機能を作成することができるということです。 –

+0

+1:便利です、ありがとうございます。 – bjskishore123

1

ビルダーパターンはビルドに特化して使用され、デコレータはビルド後に特別な機能を追加します。 例:上記のピザの例では、問題のドメインに基づいて2つのパターンのいずれかを使用することができます。

チリフレークがピザに欠かせなくても、同様にピザに追加する成分がたくさんありますが、ピザを食べやすい(意味のある状態)にするための要素がほとんどありません。 ピザが完成したら、後でトマトソース、オリーブなどの異なるトッピングで飾ることができます。

また、一緒に使うことができますが、複雑さが増します。だから、問題の領域で必要なときだけパターンを賢明に使うべきです。そうでなければ、単純な構造で十分です。

2

ビルダーデコレータのキーの特性を参照してください。

Builder:に強制的に工場とは異なりパラメータのいくつかはオプションであるかもしれないエラー

  • やすくなりますファクトリクラスにクライアントプログラムから渡すために(生成に関するパターン)

    1. 引数が多すぎますすべてのパラメータを送信する
    2. オブジェクトが重く、作成が複雑です。例えばピザ

    Decoratorの様々なタイプの構築:(構造パターン)

    1. は、実行時にオブジェクトのために行動を追加します。継承はこの機能を達成するための鍵であり、このパターンの長所と短所の両方です。
    2. インターフェイスの動作を強化します。
    3. デコレータは、コンポーネントが1つしかない縮退コンポジットと見ることができます。ただし、デコレータは、オブジェクトの集約を目的としたものではありません。
    4. デコレータデコ使用する場合はデコレータはあなたが

    をサブクラス化せずにオブジェクトに責任を追加できるように設計された再帰的構成に

  • をサポートしています。

    1. オブジェクトの責任をと動作を動的に追加/削除する必要があります。
    2. のコンクリートの実装は責任から分離し、サブとき
    3. をビヘイビアされなければならない - /クラス分けを動的に追加するにはあまりにも高価である取り除く責任

    あなたのクエリに戻って来る:

    ビルダーはのための右の生成に関するパターンですピザ。ピザは、最初は必須の成分(パンなど)で作られています。チーズ、ペパーロニ、ベーコンはオプションの成分ですが、それでも製造過程でピザの一部になることがあります。

    デコレータは、実行時にすでに作成されたオブジェクトの動的な責任を追加するのに便利です。

    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt"))); 
    

    詳細は記事下のを参照してください。

    Keeping builder in separate class (fluent interface)

    When to Use the Decorator Pattern?

  • 関連する問題