2009-03-23 11 views
25

テンプレートメソッドパターンと戦略パターンはほぼ同じことをします。私はそれらの間の基本的な違いを理解しています(テンプレートメソッドは継承ベース、ストラテジーはコンポジションベースです)。しかし、どちらを選ぶかについての適切なガイドラインはありますか?彼らは基本的に同じことをしているようです。テンプレートメソッドを使用する場合戦略?

答えて

18

私は、アルゴリズムが実行されているオブジェクトの内部についての知識が必要な場合に、テンプレートメソッドを使用します。

他のすべての場合(アルゴリズムがオブジェクトのインターフェイスを使用する必要がある場合のみ)、戦略を使用しようとします。

さらに、ストラテジーは実装する実際のアルゴリズムがある場合にのみ有効です。クラス間の唯一の違いが(たとえば)どの単純な値を返すかは、Templateメソッドを使用してください。

2

OO設計の中心的な原則の1つは、「相続財産の継承」であるため、戦略パターンを支持することを示唆しています。明らかに、あなたが特定のシナリオで達成しようとしているものに依存します。

31

戦略では、再利用可能なアルゴリズムを複数の場所で使用することができます。コンシューマーが提供し、複数の場所で使用できるアルゴリズムをお持ちの場合、これはストラテジー(ソートアルゴリズム、述部、比較関数など)の良い点です。その良い例です。

テンプレートメソッドは、ユーザーがクラスから継承し、制御された方法で実装をオーバーライドできるようにする場合に特に適しています(基本的に、すべての配管を置き換えずにそれらが基本メソッドを呼び出さなかったか、間違った時間に呼び出されたために問題が発生することはありませんでした)。

これらは類似していても、実際に行っていることに応じて同じ種類の目的を果たすことができます。 すべてのデザインパターンと同様に、実際に決定的な答えがないので、このような質問に答えることは難しいです。コンテキスト内で決定するのが実際に簡単です...

5

Nの動作の1つを変更するだけで、大きな継承ツリーを作成できます。そして、N個の動作のうちの2番目を変更するために、2番目の大きな継承ツリーを作成することができます。

また、小さな戦略ツリーを作成してツリーをアンロードすることもできます。

だから、いくつかの振る舞いにいくつかの変更を追加するだけで、より多くのクラスを追加することに気がついたら、クラスに戦略を与える時が来ました。

13

際の利用戦略を考えてみましょう:あなたのオブジェクトの動作が実行時に変更する必要が

  • 既に他の基準でクラス階層があります。
  • さまざまなクラス間で戦略ロジックを共有したいと考えています。

テンプレートパターンを使用するのに十分である必要があります。

+0

は、「これらのすべての場合」または「どちらかの場合」ですか? – xtofl

+1

「これらのいずれかが真の場合」 –

17

2人は実際に一緒に使用することができます。

パターンを実装するための特定のコードを持つレシピとしてパターンを考えないでください。

これはキーとなる設計意図であり、多くの実装が可能です。あなたのコードのどこかにパターン名を記述することによって、そのコードを書いたときにあなたの意図を読者に知らせることになります。実装は二次的です。

テンプレートメソッドは、「置き換え可能なステップを含むアルゴリズム」を提供します。 (アルゴリズムは通常、オーバーライド不可能なメソッド(finalやprivateなど)で定義されます)

この概念のGoF実装では、継承とメソッドオーバーライドを使用して、これらのステップを置き換えます。

の場合、の戦略に置き換えても、テンプレートメソッドを使用しています。

たとえば、バイナリツリーをインオーダーして歩き回り、各ノードで「何かする」クラスを考えてみましょう。

イントールは、inorder()メソッドがテンプレートメソッドであるということです。ウォークの構造は常に同じです。

"何か"を行う部分は、同じクラスのメソッドとして実装することができます(また、動作を変更するためにサブクラスでオーバーライドすることもできます)。その場合は、 "何かをする" "

+3

+1 **テンプレートメソッドは置き換え可能なステップを持つアルゴリズム** – Fuhrmanator

+1

+1デカップリング継承とテンプレートメソッド、つまり固定アルゴリズムのいくつかのステップがオブジェクト構成を使用しても置き換えられます。 –

3

私は同意したいと思います。交換可能なステップが戦略を使用して委任することができ、基本的には、「交換可能なステップとアルゴリズム」(非常によく造語) -

テンプレート=動作が上に担持されるに沿って、一般的な線描画気パターン - テンプレートをパターンのコンセプト。

戦略パターン=気にのみ結果結果は常にソートされたリストです常に並べ替えのように(いくつかの所定のルールを遵守する必要がありますが、実際のソートデdefferも操作の下線実装からクライアントを切り離すについてバブルソート、またはクイックソート)。

乾杯。

6

は、私は(this answerから)この声明に反対:

「テンプレート方法は、特にあなたが 人々があなたのクラスを継承することができるようにしたいし、それらをオーバーライドすることができ ようにしたい場合を対象として 制御された方法であなたの実装を。


あなたは人々があなたのクラスから継承したいなら、あなたは特定の実装を望むのではなく、特定の動作を希望しています。それは私にとって悪いことです。

WANTの有効なことは、アルゴリズムの個々のステップをオーバーライドしたり実装したりできることです。その目標は、テンプレートメソッド(プロテクトメソッドを選択的にオーバーライドできる)とストラテジパターン(実装をインジェクトする場所)の両方で達成できます。

アルゴリズムを実装するクラスを構築していて、そのアルゴリズムのステップを他の開発者が変更できるようにする場合は、それが必要です。あなたの唯一の決定は、継承または構成を介してそれらを許可するかどうかです。

他のすべてのものが等しいとすれば、継承よりも構成を優先する必要がありますが、私たちの目標が何であるかを最初に把握するだけで継承/合成の決定に到達する必要があります。

「私は彼らがこのクラスから継承できるようにしたい」とは決して始めません。それは馬IMOの前にカートです。

0

クライアントコードは実装に依存しないという非常に重要な理由のために、私はほとんど常に戦略に取り掛かりますが、実装のテンプレートパターン部分は抽象クラスにとどまり、抽象クラスの変更によってクライアント多くの場合、厳密なコードが生成され、「これは私が予想していたよりも大きな変化となった」というデベロッパーに終わりました。

しかし、それは抽象クラスで共通のコードを取得するには本当に便利であるときのケースでは、私はそれを行うことを躊躇しても、クライアントコードに関連するコードを維持しようとしないだろう離れてから

0

私の要約:戦略パターン一般的には良いことであるTemplate Methodパターンよりも疎結合しています。

TEMPLATE METHOD & STRATEGY: Inheritance vs. Delegation

ロバートC.マーティンしたがって、戦略パターンは テンプレートメソッドパターンを介して1つの余分な利点を提供します。 TEMPLATE METHODパターンは、 汎用アルゴリズムが多くの可能な詳細 の実装を操作することを可能にするが、DIPを完全に遵守することにより、 はさらに詳細な実装を 多くの異なる汎用アルゴリズムによって操作することができる。

ディップ依存性逆転原理である:

A.高レベルモジュールは、低レベルのモジュールに依存してはなりません。どちらも抽象に依存するはずです。 B.抽象は細部に依存すべきではありません。詳細は抽象化に依存する必要があります。

WikipediaおよびMartin again)。

-1

両方の組み合わせを使用して、デフォルトの実装(Templateパターンから)を戦略パターンのContextクラスにダンプすることをお勧めします。このようにして、アルゴリズムのステップの実行順序が制御されたままになるように、呼び出したいメソッドをユーザーが呼び出すようにすることができます。

/** 
* enables replaceable steps in algorithm 
*/ 
public interface HouseStrategy{ 
     void buildWalls(); 
     void buildPillars(); 
} 


public class HouseContext{ 


    //public API that enforces order of execution 
    public void build(HouseStrategy strategy){ 
     buildFoundation();//default implementation 
     strategy.buildPillars();//delegated to concrete strategy 
     strategy.buildWalls();//delegated to concrete strategy 
     buildWindows();//default implementation 
    } 

    //default implementation 
    private void buildWindows() { 
     System.out.println("Building Glass Windows"); 
    } 
    //default implementation 
    private void buildFoundation() { 
     System.out.println("Building foundation with cement,iron rods and sand"); 
    } 

} 

public class WoodenHouse implements HouseStrategy { 

    @Override 
    public void buildWalls() { 
     System.out.println("Building Wooden Walls"); 
    } 

    @Override 
    public void buildPillars() { 
     System.out.println("Building Pillars with Wood coating"); 
    } 

} 

public class GlassHouse implements HouseStrategy { 

    @Override 
    public void buildWalls() { 
     System.out.println("Building Wooden Of glass"); 
    } 

    @Override 
    public void buildPillars() { 
     System.out.println("Building Pillars with glass coating"); 
    } 

} 

具体的な戦略はまだ拡張可能です。

public class GlassHouse implements HouseStrategy,EarthquakeResistantHouseStrategy{......} 

、のように私はここを参照してください用法

HouseContext context = new HouseContext(); 

    WoodenHouse woodenHouseStrategy = new WoodenHouse(); 
    context.build(woodenHouseStrategy); 

    GlassHouse glassHouseStrategy = new GlassHouse(); 
    context.build(glassHouseStrategy); 

一つの欠点は、具体的な戦略が唯一のアルゴリズムすなわちbuildWalls()とbuildPillars()のバリアントの動作を変更することができるということです。不変部分、つまりbuildFoundation()とbuildWindows()を変更する必要がある場合は、新しい動作を実装する別のContextクラスを作成する必要があります。 純粋な戦略パターンにはないコードの再利用性があります:-)

関連する問題