回答:
これら2つのパターンの違いを説明するために、いくつかのGoFデザインパターンのカプセル化階層テーブルを含めています。うまくいけば、それがそれぞれがカプセル化するものをよりよく説明するので、私の説明はより意味があります。
まず、階層には、特定のパターンが適用されるスコープ、またはテーブルのどちら側から開始するかに応じて、詳細レベルをカプセル化するために使用する適切なパターンが一覧表示されます。
この表からわかるように、戦略パターンオブジェクトはアルゴリズムの実装の詳細を隠しているため、異なる戦略オブジェクトを使用しても同じ機能を実行できますが、方法は異なります。各戦略オブジェクトは、特定の要因に合わせて最適化されるか、他のパラメーターで動作します。また、共通のインターフェースを使用することで、コンテキストはどちらでも安全に機能します。
コマンドパターンは、アルゴリズムよりもはるかに小さな詳細レベルをカプセル化します。オブジェクトにメッセージを送信するために必要な詳細(レシーバー、セレクター、引数)をエンコードします。プロセス実行のこのようなごく一部をオブジェクト化することの利点は、そのようなメッセージを、詳細をハードコードする必要なしに、一般的な方法で異なる時点または場所に沿って呼び出すことができることです。これにより、特定の呼び出しの詳細を実行前に知る必要なく、メッセージを1回以上呼び出すか、システムのさまざまな部分または複数のシステムに渡すことができます。
設計パターンでは一般的ですが、パターン名を付けるためにすべての実装が詳細に同一である必要はありません。詳細は、実装や、オブジェクト内でエンコードされるデータと、メソッド引数としてエンコードされるデータとで異なります。
戦略はアルゴリズムをカプセル化します。コマンドは、要求の送信者と受信者を分離し、要求をオブジェクトに変換します。
それがアルゴリズムの場合、どのように実行されるか、戦略を使用します。メソッドの呼び出しとその実行を分離する必要がある場合は、コマンドを使用します。コマンドは、タスクやトランザクションなど、後で使用するためにメッセージをキューに入れるときによく使用されます。
非常に古い質問に答えます。(誰かが最も投票されたのではなく最新の回答を見ていますか?)
似ているため、混乱するのは当然です。戦略パターンとコマンドパターンはどちらもカプセル化を利用しています。しかし、それはそれらを同じにしません。
主な違いは、何がカプセル化されているかを理解することです。OOの原則は、どちらのパターンも依存し、変化するものをカプセル化することです。
戦略の場合、変化するのはアルゴリズムです。たとえば、1つの戦略オブジェクトはXMLファイルに出力する方法を知っており、他のオブジェクトはJSONなどに出力します。異なるアルゴリズムは、異なるクラスに保持(カプセル化)されます。それはそれと同じくらい簡単です。
コマンドの場合、変化するのはリクエスト自体です。要求から来るかもしれないFile Menu > Delete
か、Right Click > Context Menu > Delete
またはJust Delete Button pressed
。3つのケースすべてで、同じタイプの3つのコマンドオブジェクトを生成できます。これらのコマンドオブジェクトは、削除の3つの要求のみを表します。削除アルゴリズムではありません。リクエストはオブジェクトの束なので、簡単に管理できました。突然、取り消しややり直しなどの機能を提供することは簡単になります。
コマンドが要求されたロジックをどのように実装するかは重要ではありません。execute()を呼び出すと、削除をトリガーするアルゴリズムを実装したり、削除を他のオブジェクトに委任したり、戦略に委任したりすることもできます。コマンドパターンの実装詳細のみです。それは次のように命名された理由はここにあるコマンド、それはへの丁寧な方法はありませんが、要求: - )
戦略とは対照的です。このパターンは、実行される実際のロジックにのみ関係します。そうすることで、最小限のクラスセットでさまざまな動作の組み合わせを実現でき、クラスの爆発を防ぐことができます。
Commandはカプセル化の理解を広げるのに役立ち、Strategyはカプセル化とポリモーフィズムの自然な使用を提供します。
私の見方では、同じことを行うには複数の方法があり、それぞれが戦略であり、実行時に何かがどの戦略を実行するかを決定します。
最初にStrategyOneを試してみてください。結果が十分でない場合は、StrategyTwoを試してください...
コマンドは、TryToWalkAcrossTheRoomCommandのように、発生する必要のある明確なものにバインドされています。このコマンドは、一部のオブジェクトが部屋を横断しようとするたびに起動されますが、その内部では、部屋を横断しようとするためにStrategyOneおよびStrategyTwoを試行する場合があります。
マーク
私の考えでは間違っているかもしれませんが、私はコマンドを実行する機能、または反応として扱います。少なくとも2人のプレーヤーが必要です。アクションを要求するプレーヤーと、アクションを実行するプレーヤーです。GUIはコマンドパターンの典型的な例です。
コマンドは通常、いくつかのスコープまたはビジネスエリアにバインドされますが、必須ではありません。請求書を発行したり、ロケットを起動したり、execute()
1つのアプリケーション内で同じインターフェイス(たとえば、単一のメソッド)を実装するファイルを削除したりするコマンドがある場合があります。多くの場合、コマンドは自己完結型であるため、意図したタスクを処理するためにエグゼキュータから何も必要ありません(必要な情報はすべて構築時に提供されます)。コマンドは状況依存であり、このコンテキストを検出できるはずです(Backspaceコマンドは、前の文字を正しく削除するためにテキスト内のキャレット位置を知っている必要があります。Rollbackコマンドは、現在のトランザクションを検出してロールバックする必要があります; ...)
戦略は少し異なっている:それはいくつかのエリアにより結合しています。戦略は、日付をフォーマットするルール(UTC?ロケール固有?)( "日付フォーマッター"戦略)、または幾何学的図形の正方形を計算するルール( "正方形計算機"戦略)を定義します。戦略とは、この意味で、フライウェイトオブジェクトであり、何かを入力(「日付」、「図」など)として取り、それに基づいて何らかの決定を行います。おそらく戦略のない最高の良い例は、と接続された一方でjavax.xml.transform.Source
インターフェース:渡されたオブジェクトがあるかどうかに応じてDOMSource
、またはSAXSource
あるいはStreamSource
戦略(= XSLTトランスこの場合)、それを処理するための異なるルールを適用します。実装は単純なものでswitch
も、責任の連鎖パターンを伴うものでもかまいません。
しかし、実際、これら2つのパターンの間には共通点があります。コマンドと戦略は、同じセマンティック領域内でアルゴリズムをカプセル化します。
コマンド:
基本コンポーネント:
execute()
ワークフロー:
クライアントがInvokerを呼び出す=> InvokerがConcreteCommandを呼び出す => ConcreteCommandが、抽象的なCommandメソッドを実装するReceiverメソッドを呼び出す。
利点:クライアントはコマンドとレシーバーの変更に影響を与えません。インボーカーは、クライアントとレシーバーの間の疎結合を提供します。同じInvokerで複数のコマンドを実行できます。
コマンドパターンを使用すると、同じ Invokerを使用して異なるレシーバーでコマンドを実行できます。呼び出し側はレシーバーのタイプを認識していません
概念をよりよく理解するには、Wikipediaのリンクに加えて、Pankaj KumarによるこのJournalDevの記事とJames Sugrueによるdzoneの記事をご覧ください。
コマンドパターンを使用して
コマンドの呼び出し側と受信側を分離する
コールバックメカニズムを実装する
元に戻すおよびやり直し機能を実装する
コマンドの履歴を維持する
java.lang.Thread
コマンドパターンの1つの優れた実装です。スレッドは、Runnableを具現化するインボーカーおよびクラスとして、ConcreteCommonad / Receiverrun()
として、メソッドとしてはCommandとして扱うことができます。
コマンドパターンの元に戻す/やり直しバージョンは、Theodore Norvellの 記事で読むことができます。
戦略:
戦略パターンは非常に簡単に理解できます。このパターンは
アルゴリズムには複数の実装があり、アルゴリズムの実装は特定の条件に応じて実行時に変更される可能性があります。
航空会社予約システムの運賃コンポーネントの例を見てみましょう
航空会社は、ピーク期間とオフピーク期間の異なる期間に異なる運賃を提供したいと考えています。オフピークの旅行日には、魅力的な割引を提供することで需要を刺激したいと考えています。
戦略パターンの重要なポイント:
コード例を含む関連記事:
私にとって、違いは意図の1つです。両方のパターンの実装はかなり似ていますが、目的が異なります。
ストラテジーの場合、オブジェクトを使用するコンポーネントはオブジェクトが何をするかを知っています(そしてそれを使用して独自の作業の一部を実行します)が、それがどのように行われるかは気にしません。
コマンドの場合は、オブジェクトを使用してコンポーネントはどちらも知らない何のコマンドがありませんでもどのように、それはそれをしない-それはちょうどそれを起動する方法を知っています。呼び出し元のタスクは、コマンドを実行することだけです。コマンドによって実行される処理は、呼び出し元の中核作業の一部を形成しません。
これが違いです-コンポーネントを使用するオブジェクトは、コンポーネントが何をするかを実際に知っているか、気にしますか?ほとんどの場合、これはパターンオブジェクトが呼び出し元に値を返すかどうかに基づいて決定できます。呼び出し元がパターンオブジェクトの動作に関心がある場合、おそらく何かを返すようにして、それが戦略になります。戻り値を気にしない場合、それはコマンドである可能性があります(注:Java Callableのようなものはまだコマンドです。なぜなら、値を返しますが、呼び出し元は値を気にしないため、単にそれを返します。最初にコマンドを提供したものに)。