回答:
正直なところ、2つのパターンは実際にはかなり似ており、それらの間の明確な違いは、質問する人によって異なる傾向があります。一般的な選択肢は次のとおりです。
「クラシック」な実装は、リストのすべての項目の状態または戦略のいずれかに一致しますが、両方が混在するハイブリッドにまたがって実行します。特定のものがより国家的であるか戦略的であるかは最終的に主観的な質問です。
getStatus()
、オブジェクトの状態に基づいて異なるステータスを返すメソッドがある場合でも、
メソッドの呼び出し元を、それぞれの潜在的な状態に対応するために別の方法でコーディングする必要はありません。違いは、それらが異なる問題を解決するということです。
ただし、これらの異なる目標を達成するための構成は非常に似ています。どちらのパターンも、委任による構成の例です。
それらの利点に関するいくつかの観察:
使用して状態パターンを状態保持(コンテキスト)クラスの知識から解放されるものがある状態またはタイプとどのように入手可能である状態またはタイプ。これは、クラスが開閉式設計原則(OCP)に準拠していることを意味します。クラスは、どのような状態/タイプがあるかを変更するために閉じられますが、状態/タイプは拡張に対して開かれています。
Strategyパターンを使用することにより、アルゴリズムを使用する(コンテキスト)クラスは、特定のタスク(-「アルゴリズム」)を実行する方法の知識から解放されます。このケースは、OCPへの準拠も作成します。このタスクを実行する方法に関する変更のためにクラスはクローズされていますが、このタスクを解決するための他のアルゴリズムの追加に対して設計は非常にオープンです。
これにより、コンテキストクラスの単一責任原則(SRP)への準拠も改善される可能性があります。さらに、アルゴリズムは他のクラスによる再利用が容易になります。
誰かが素人の言葉で説明してくれませんか?
デザインパターンは実際には「素人」の概念ではありませんが、できるだけ明確にするようにします。設計パターンは3次元で検討できます。
状態と戦略を比較してみましょう。
状態は2つのケースのいずれかで使用されます[GoF book p。306]:
- オブジェクトの動作はその状態に依存し、その状態に応じて実行時にオブジェクトの動作を変更する必要があります。
- 操作には、オブジェクトの状態に依存する大きなマルチパート条件ステートメントがあります。この状態は通常、1つ以上の列挙定数で表されます。多くの場合、いくつかの操作にはこの同じ条件構造が含まれます。Stateパターンは、条件の各ブランチを個別のクラスに配置します。これにより、オブジェクトの状態を、他のオブジェクトとは独立して変化することができるそれ自体がオブジェクトとして扱うことができます。
Stateパターンが実際に解決する問題があることを確認したい場合は、有限状態マシンを使用してオブジェクトの状態をモデル化できるはずです。ここに適用例があります。
各状態遷移は、Stateインターフェースのメソッドです。これは、設計では、このパターンを適用する前に、状態遷移についてかなり確実にする必要があることを意味します。それ以外の場合、遷移を追加または削除すると、インターフェースとそれを実装するすべてのクラスを変更する必要があります。
私は個人的にはこのパターンが有用だとは思いませんでした。ルックアップテーブルを使用して有限状態機械をいつでも実装できます(オブジェクト指向の方法ではありませんが、かなりうまくいきます)。
戦略は、次の[GoFブックp。316]:
- 関連するクラスの多くは、動作のみが異なります。戦略は、多くの動作の1つでクラスを構成する方法を提供します。
- アルゴリズムのさまざまなバリアントが必要です。たとえば、異なる空間/時間のトレードオフを反映するアルゴリズムを定義できます。これらのバリアントがアルゴリズムのクラス階層として実装されている場合、戦略を使用できます[HO87]。
- アルゴリズムは、クライアントが知らないはずのデータを使用します。Strategyパターンを使用して、複雑なアルゴリズム固有のデータ構造を公開しないようにします。
- クラスは多くの動作を定義し、それらはその操作で複数の条件ステートメントとして表示されます。多くの条件文の代わりに、関連する条件分岐を独自の戦略クラスに移動します。
ストラテジーを適用する最後のケースは、「条件付きのポリモーフィズムへの置き換え」として知られるリファクタリングに関連しています。
概要:国家と戦略は非常に異なる問題を解決します。問題を有限状態機械でモデル化できない場合、おそらく状態パターンは適切ではありません。問題が複雑なアルゴリズムのバリアントのカプセル化に関するものではない場合、戦略は適用されません。
状態には、次のUMLクラス構造があります。
Strategyの UMLクラス構造は次のとおりです。
要約:静的構造の点では、これら2つのパターンはほとんど同じです。実際には、のようなパターン検出ツールこれは「と考えるの構造は、[...]パターン(例えば、概念的な情報を参照することなく)自動プロセスによって、それらの区別を禁止する、同じです。」
ただし、ConcreteStatesが状態遷移を自分で決定する場合は、大きな違いが生じる可能性があります(上の図の「かもしれない」の関連付けを参照してください)。これにより、具象状態が結合されます。たとえば(次のセクションを参照)、状態Aは状態Bへの遷移を決定します。Contextクラスが次の具象状態への遷移を決定すると、これらの依存関係はなくなります。
上記の問題のセクションで述べたように、国家は、実行時の動作の変更がいくつかに依存することを意味状態オブジェクトの。したがって、有限状態マシンの関係で説明したように、状態遷移の概念が適用されます。[GoF]は、遷移は、ConcreteStateサブクラスまたは集中型の場所(テーブルベースの場所など)で定義できると述べています。
単純な有限状態機械を想定しましょう:
サブクラスが状態遷移を決定すると(次の状態オブジェクトを返すことにより)、ダイナミックは次のようになります。
Strategyのダイナミクスを示すには、実際の例を借用すると便利です。
概要:各パターンは、ポリモーフィックコールを使用して、コンテキストに応じて何かを行います。状態パターンでは、ポリモーフィックな呼び出し(遷移)により、次の状態に変化が生じることがよくあります。Strategyパターンでは、通常、ポリモーフィックな呼び出しはコンテキストを変更しません(たとえば、一度クレジットカードで支払うことは、次回PayPalで支払うことを意味しません)。繰り返しますが、状態パターンのダイナミクスは、対応するfininteステートマシンによって決定されます。
戦略パターンでは、アルゴリズムの実装をホスティングクラスから移動し、別のクラスに配置します。これは、ホストクラスが各アルゴリズム自体の実装を提供する必要がないことを意味します。これは、不明瞭なコードにつながる可能性があります。
並べ替えアルゴリズムは、すべて同じ種類の処理(並べ替え)を行うため、通常は例として使用されます。異なる並べ替えアルゴリズムをそれぞれ独自のクラスに配置すると、クライアントは使用するアルゴリズムを簡単に選択でき、パターンはそれにアクセスする簡単な方法を提供します。
状態パターンには、オブジェクトの状態が変化したときにオブジェクトの動作を変更することが含まれます。これは、ホストクラスが、すべての異なる状態の動作の実装を提供していないことを意味します。ホストクラスは通常、特定の状態で必要な機能を提供するクラスをカプセル化し、別のクラスに切り替えます状態が変化したとき。
カスタマーコールを処理するIVR(インタラクティブボイスレスポンス)システムを検討してください。次の顧客を処理するようにプログラムすることができます。
この状況を処理するには、状態パターンを使用できます。
顧客をサポートエグゼクティブに接続するこのプロセス自体は、次のいずれかに基づいてエグゼクティブが選ばれる戦略パターンを使用して実装できます。
戦略パターンは「どのように」アクションを実行するかを決定し、状態パターンは「いつ」アクションを実行するかを決定します。
戦略:戦略は固定されており、通常はいくつかのステップで構成されます。(ソートは1つのステップのみを構成するため、このパターンの目的を理解するには原始的すぎるため、非常に悪い例です)。戦略の「メイン」ルーチンがいくつかの抽象メソッドを呼び出しています。たとえば、「Enter Room Strategy」、「main-method」はgoThroughDoor()で、次のようになります。openDoor(); enterRoom(); 順番(); closeDoor(); if(wasLocked())lockDoor();
ロックされている可能性のあるドアを介して1つの部屋から別の部屋に移動するためのこの一般的な「アルゴリズム」のサブクラスは、アルゴリズムのステップを実装できます。
つまり、戦略をサブクラス化しても基本的なアルゴリズムは変更されず、個々のステップのみが変更されます。
上記はテンプレートメソッドパターンです。次に、一緒に属するステップ(ロック解除/ロックおよびオープン/クローズ)を独自の実装オブジェクトに入れ、それらに委任します。たとえば、キー付きロックとコードカード付きロックは2種類のロックです。戦略から「ステップ」オブジェクトに委任します。これで戦略パターンが完成しました。
状態パターンは完全に異なるものです。
あなたはラッピングオブジェクトとラップされたオブジェクトを持っています。包まれたものが「状態」です。状態オブジェクトは、そのラッパーを介してのみアクセスされます。これで、いつでもラップされたオブジェクトを変更できるため、ラッパーはその状態、または「クラス」やタイプさえも変更しているように見えます。
たとえば、ログオンサービスがあるとします。ユーザー名とパスワードを受け入れます。logon(String userName、String passwdHash)という1つのメソッドしかありません。ログオンを受け入れるかどうかを自分で決定する代わりに、状態オブジェクトに決定を委任します。その状態オブジェクトは通常、ユーザーとパスの組み合わせが有効かどうかを確認し、ログオンを実行します。しかし、今では、「チェッカー」を、特権ユーザーのみがログオンできるようにする(メインテナンス時など)か、誰もログオンできないようにすることで交換できます。これは、「チェッカー」がシステムの「ログオン状態」を表すことを意味します。
最も重要な違いは次のとおりです。戦略を選択したときは、それが終わるまでそれを堅持します。つまり、その「メインメソッド」を呼び出し、そのメソッドが実行されている限り、戦略を変更することはありません。OTOHは、システムの実行時の状態パターンの状況で、状況に応じて任意に状態を変更します。
戦略パターンは、特定のタスクに複数のアルゴリズムがあり、クライアントが実行時に使用する実際の実装を決定する場合に使用されます。
Wikiの戦略パターン記事のUML図:
主な機能:
詳細と実際の例については、この投稿を参照してください。
状態パターンにより、内部状態が変化したときにオブジェクトの動作を変更できます
ウィキの状態パターン記事からのUML図 :
オブジェクトの状態に基づいてオブジェクトの動作を変更する必要がある場合は、オブジェクトに状態変数を設定し、if-else条件ブロックを使用して、状態に基づいてさまざまなアクションを実行できます。状態パターンは、コンテキストと状態の実装を通じてこれを達成するための体系的で結合された方法を提供するために使用されます。
詳細については、このjournaldevの記事を参照してください。
ソースメイキングとjournaldevの記事との主な違い:
どちらのパターンもいくつかの派生クラスを持つ基本クラスに委譲しますが、これらの派生クラスがコンテキストクラスへの参照を保持するのはStateパターン内だけです。
別の見方をすると、戦略パターンは状態パターンのより単純なバージョンです。必要に応じて、サブパターン。派生した状態で参照をコンテキストに戻すかどうか(つまり、コンテキストでメソッドを呼び出すかどうか)は、実際に依存します。
詳細については、Robert C Martin(およびMicah Martin)が彼らの著書「C#でのアジャイル原則、パターン、および実践」でこれに答えています。(http://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258)
これはかなり古い質問ですが、それでも私は同じ答えを探していましたが、これは私が発見したものです。
状態パターンについて、内側のプレーヤーの再生ボタンの例を考えてみましょう。再生すると、再生が開始され、再生中であることがコンテキストに認識されます。クライアントは再生操作を実行するたびに、プレーヤーの現在の状態を確認します。これでクライアントは、オブジェクトの状態がコンテキストオブジェクトを介して再生されていることを認識できるため、状態オブジェクトの一時停止アクションメソッドを呼び出します。クライアントの状態を認識し、アクションを実行するために必要な状態を自動化できます。
https://www.youtube.com/watch?v=e45RMc76884 https://www.tutorialspoint.com/design_pattern/state_pattern.htm
戦略パターンの場合、クラス図の配置は状態パターンと同じです。クライアントは、いくつかの操作を行うためにこの配置になります。つまり、さまざまな状態の代わりに、たとえば、パターンに対して実行する必要があるさまざまな分析など、さまざまなアルゴリズムがあります。ここでクライアントは、何をしたいのか、どのアルゴリズム(ビジネス定義のカスタムアルゴリズム)を実行するかをコンテキストに伝え、それを実行します。
https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm
どちらもオープンクローズの原則を実装しているため、開発者は状態パターンと新しいアルゴリズムに新しい状態を追加できます。
しかし、違いは、オブジェクトの状態に基づいてさまざまなロジックを実行するために使用される状態パターンである、それらが使用されるものです。そして戦略のケースでは異なるロジック。
違いはhttp://c2.com/cgi/wiki?StrategyPatternで説明されています。データ分析の全体的なフレームワーク内でさまざまなアルゴリズムを選択できるようにするために、Strategyパターンを使用しました。これにより、フレームワーク全体とそのロジックを変更せずにアルゴリズムを追加できます。
典型的な例は、あなたが関数を最適化するためのフレームワークを持っていることです。フレームワークはデータとパラメータを設定します。戦略パターンでは、フレームワークを変更せずに、sttepest descents、共役勾配法、BFGSなどのアルゴリズムを選択できます。
2つのタスクに分割できるプロジェクトがある場合:
タスク1:次の2つのアルゴリズムのいずれかを使用して実行できます:alg1、alg2
タスク2:3つの異なるアルゴリズムのいずれかを使用して、alg3、alg4、alg5を実行できます。
alg1とalg2は交換可能です。alg3、alg4、alg5は交換可能です。
タスク1とタスク2で実行するアルゴリズムの選択は、状態によって異なります。
状態1:タスク1にalg1、タスク2にalg3が必要
状態2:タスク1にalg2、タスク2にalg5が必要
コンテキストにより、状態オブジェクトを状態1から状態2に変更できます。その後、alg1とalg3ではなく、alg2とalg5によってタスクが実行されます。
タスク1またはタスク2にはさらに互換性のあるアルゴリズムを追加できます。これは戦略パターンです。
タスク1とタスク2では、アルゴリズムの異なる組み合わせでより多くの状態を設定できます。状態パターンを使用すると、ある状態から別の状態に切り替えて、アルゴリズムの異なる組み合わせを実行できます。
「戦略」は、必要に応じてさまざまな状況で変更できるアルゴリズムにすぎず、何かを処理します。例 ファイルの圧縮方法を選択できます。メソッドのzipまたはrar ...
しかし、「状態」は、オブジェクトのすべての動作を変更できます。変更すると、他のフィールドを変更することもできます...そのため、所有者への参照があります。オブジェクトフィールドを変更すると、オブジェクトの動作がまったく変わる可能性があることに注意してください。例 objでState0をState1に変更すると、整数が10に変更されます。そのため、何らかの計算を行ってその整数を使用するobj.f0()を呼び出すと、結果に影響します。