StrategyデザインパターンとStateデザインパターンの違いは何ですか?ウェブ上でかなりの数の記事を読んでいたが、違いをはっきりとは確認できなかった。
誰かが素人の用語の違いを説明してもらえますか?
正直なところ、2つのパターンは実際にはかなり似ており、それらの定義の違いは、尋ねる人によって異なる傾向があります。一般的な選択肢は次のとおりです。
「クラシック」な実装は、リスト上のすべてのアイテムの状態または戦略のいずれかと一致しますが、両方が混在するハイブリッドを実行します。特定のものがState-yであるかStrategy-yであるかは、最終的に主観的な問題です。
getStatus()
メソッドがありますが、メソッドの呼び出し元は、潜在的な状態ごとに異なるコードを記述する必要はありません。違いは単に、さまざまな問題を解決することです。
ただし、これらのさまざまな目標を達成するための構成は非常に似ています。両方のパターンは、委任を伴う構成の例です。
利点に関するいくつかの観察:
Stateパターンを使用することにより、状態保持(コンテキスト)クラスはwhat状態またはタイプの知識から解放され、使用可能な状態またはタイプ。これは、クラスがOpen-Closed Design Principle(OCP)に準拠していることを意味します。クラスは、存在するステート/タイプの変更に対してクローズされますが、ステート/タイプは拡張に対してオープンです。
Strategyパターンを使用することにより、アルゴリズムを使用する(コンテキスト)クラスは、特定のタスクを実行するためのhowの知識から解放されます( -「アルゴリズム」)。この場合も、OCPへの準拠を作成します。このタスクを実行する方法に関する変更のためにクラスは閉じられていますが、設計はこのタスクを解決するための他のアルゴリズムの追加に対して非常に開かれています。
これにより、コンテキストクラスの単一責任原則(SRP)の遵守も向上する可能性があります。さらに、アルゴリズムは他のクラスで再利用できるようになります。
誰かが素人の言葉で説明してもらえますか?
デザインパターンは、実際には「素人」の概念ではありませんが、できるだけ明確にするようにします。すべてのデザインパターンは、次の3つの次元で検討できます。
状態と戦略を比較しましょう。
Stateは2つのケースのいずれかで使用されます [GoF book p。306] :
- オブジェクトの動作はその状態に依存し、その状態に応じて実行時に動作を変更する必要があります。
- 操作には、オブジェクトの状態に依存する大規模なマルチパート条件文があります。この状態は通常、1つ以上の列挙定数で表されます。多くの場合、複数の操作にこの同じ条件構造が含まれます。 Stateパターンは、条件の各ブランチを個別のクラスに配置します。これにより、オブジェクトの状態を、他のオブジェクトとは独立して変化する可能性のあるオブジェクトとして扱うことができます。
状態パターンが解決する問題を確実に解決したい場合は、有限状態マシンを使用してオブジェクトの状態をモデル化できるはずです。適用例 here を見つけることができます。
各状態遷移は、Stateインターフェースのメソッドです。これは、設計の場合、このパターンを適用する前に状態遷移についてかなり確実にする必要があることを意味します。それ以外の場合、トランジションを追加または削除する場合、インターフェイスとそれを実装するすべてのクラスを変更する必要があります。
私は個人的にこのパターンが有用であるとは感じていません。ルックアップテーブルを使用して、いつでも有限状態マシンを実装できます(OOの方法ではありませんが、うまく機能します)。
Strategyは次の場合に使用されます [GoF book p。316] :
- 多くの関連クラスは、動作のみが異なります。戦略は、多くの動作の1つでクラスを構成する方法を提供します。
- アルゴリズムのさまざまなバリアントが必要です。たとえば、異なる空間/時間のトレードオフを反映するアルゴリズムを定義できます。これらのバリアントがアルゴリズムのクラス階層として実装される場合、戦略を使用できます[HO87]。
- アルゴリズムは、クライアントが知らないデータを使用します。 Strategyパターンを使用して、複雑なアルゴリズム固有のデータ構造を公開しないようにします。
- クラスは多くの振る舞いを定義し、それらはその操作において複数の条件文として現れます。多くの条件の代わりに、関連する条件分岐を独自の戦略クラスに移動します。
ストラテジーを適用する最後のケースは、 条件付きポリモーフィズムを置換 として知られるリファクタリングに関連しています。
Summary: StateとStrategyは、非常に異なる問題を解決します。問題を有限状態マシンでモデル化できない場合、状態パターンは適切ではない可能性があります。問題が複雑なアルゴリズムのバリアントをカプセル化することではない場合、戦略は適用されません。
StateのUMLクラス構造は次のとおりです。
StrategyのUMLクラス構造は次のとおりです。
概要:静的構造に関しては、これら2つのパターンはほとんど同じです。実際、 this one などのパターン検出ツールは、「 [...]パターンの構造は同一であり、自動プロセスによる区別を禁止しています(参照せずに、概念的な情報へ)
ただし、ConcreteStatesが自身で状態遷移を決定する場合、大きな違いが生じる可能性があります(上の図の「mightdetermined」関連付けを参照)。これにより、具体的な状態が結合されます。たとえば、次のセクションを参照してください。状態Aは状態Bへの遷移を決定します。Contextクラスが次の具体的な状態への遷移を決定すると、これらの依存関係はなくなります。
上記の問題のセクションで述べたように、Stateは、オブジェクトの一部のstateに応じて実行時に動作が変化することを意味します。したがって、有限状態マシンの関係で説明したように、状態遷移の概念が適用されます。 [GoF]は、遷移はConcreteStateサブクラスで、または中央の場所(テーブルベースの場所など)で定義できることに言及しています。
単純な有限状態マシンを仮定しましょう:
サブクラスが(次の状態オブジェクトを返すことで)状態遷移を決定すると仮定すると、ダイナミックは次のようになります。
Strategyのダイナミクスを示すには、 実際の例 を借用すると便利です。
Summary:各パターンは多態的な呼び出しを使用して、コンテキストに応じて何かを行います。状態パターンでは、多態的な呼び出し(遷移)により、次の状態が変更されることがよくあります。戦略パターンでは、ポリモーフィックコールは通常、コンテキストを変更しません(たとえば、クレジットカードによる支払いは、Paypalによる次回の支払いを意味しません)。繰り返しますが、状態パターンのダイナミクスは、対応する最終状態マシンによって決定されます。
戦略パターンには、アルゴリズムの実装をホスティングクラスから移動し、別のクラスに配置することが含まれます。これは、Hostクラスが各アルゴリズム自体の実装を提供する必要がないことを意味します。これにより、コードが不明瞭になる可能性があります。
ソートアルゴリズムは、すべて同じ種類のこと(ソート)を行うため、通常は例として使用されます。異なるソートアルゴリズムがそれぞれ独自のクラスに配置されている場合、クライアントは使用するアルゴリズムを簡単に選択でき、パターンはそれにアクセスする簡単な方法を提供します。
状態パターンには、オブジェクトの状態が変化したときにオブジェクトの動作を変更することが含まれます。これは、Hostクラスが、すべての異なる状態に対して動作の実装を提供していないことを意味します。Hostクラスは、通常、特定の状態で必要な機能を提供するクラスをカプセル化し、別のクラスに切り替えます状態が変化したとき。
ストラテジーは、開始と終了の結果が同じで、内部的に異なる方法を使用して、何かを「実行」するオブジェクトを表します。その意味で、それらは動詞の実装を表すことに似ています。状態パターンOTOHは、何かの「ある」オブジェクト、つまり操作の状態を使用します。それらはそのデータに対する操作も表すことができますが、動詞よりも名詞の表現に似ており、ステートマシン向けに調整されています。
カスタマーコールを処理するIVR(Interactive Voice Response)システムを検討してください。次の顧客を処理するようにプログラムできます。
この状況を処理するには、State Patternを使用できます。
顧客をサポートエグゼクティブに接続するこのプロセスは、Strategy Patternを使用して実装できます。この場合、エグゼクティブは次のいずれかに基づいて選出されます。
戦略パターンは「how」でアクションを実行し、状態パターンは「when」でアクションを実行します。
戦略:戦略は固定されており、通常はいくつかのステップで構成されています。 (並べ替えは1つのステップのみを構成するため、このパターンの目的を理解するには原始的すぎるため、非常に悪い例です)。戦略の「メイン」ルーチンは、いくつかの抽象メソッドを呼び出しています。例えば。 「部屋戦略に入る」、「main-method」はgoThroughDoor()で、次のようになります。approachDoor()、if(locked())openLock(); openDoor(); enterRoom();順番(); closeDoor(); if(wasLocked())lockDoor();
鍵のかかったドアを通ってある部屋から別の部屋に移動するためのこの一般的な「アルゴリズム」のサブクラスは、アルゴリズムのステップを実装できます。
言い換えれば、戦略をサブクラス化しても、基本的なアルゴリズムは変更されず、個々のステップのみが変更されます。
上記はテンプレートメソッドパターンです。次に、一緒に属するステップ(ロック解除/ロックおよびオープン/クローズ)を独自の実装オブジェクトに入れ、それらに委任します。例えば。キー付きロックとコードカード付きロックは、2種類のロックです。戦略から「ステップ」オブジェクトに委任します。これで、戦略パターンができました。
状態パターンは完全に異なるものです。
ラッピングオブジェクトとラップされたオブジェクトがあります。ラップされたものは「状態」です。状態オブジェクトは、ラッパーを介してのみアクセスされます。ラップされたオブジェクトはいつでも変更できるようになったため、ラッパーはその状態、またはその「クラス」またはタイプを変更するように見えます。
例えば。ログオンサービスがあります。ユーザー名とパスワードを受け入れます。 1つのメソッド(logon(String userName、String passwdHash))のみがあります。ログオンを受け入れるかどうかを自分で決定する代わりに、決定を状態オブジェクトに委任します。その状態オブジェクトは通常、ユーザーとパスの組み合わせが有効であるかどうかを確認し、ログオンを実行します。しかし、今では、「チェッカー」を、権限のあるユーザーのみがログオンできるようにする(メインタニング時間中など)か、誰もログオンできないようにすることで交換できます。つまり、「チェッカー」はシステムの「ログオン状態」を表します。
最も重要な違いは、戦略を選択したら、それが完了するまでそれを使い続けることです。つまり、その「メインメソッド」を呼び出し、そのメソッドが実行されている限り、戦略を変更することはありません。システムの実行中に状態パターンの状態にあるOTOHは、必要に応じて状態を任意に変更します。
Strategyパターンは、特定のタスクに複数のアルゴリズムがあり、クライアントが実際の実装を決定するときに使用されます実行時に使用されます。
wiki 戦略パターンの記事のUML図:
主な機能:
詳細と実際の例については、この投稿を参照してください。
Stateパターンにより、オブジェクトは内部状態が変化したときに動作を変更できます
wiki 状態パターンの記事のUML図:
オブジェクトの状態に基づいてオブジェクトの動作を変更する必要がある場合、オブジェクトに状態変数を設定し、if-else条件ブロックを使用して、状態に基づいてさまざまなアクションを実行できます。 Stateパターンを使用して、ContextおよびState実装。
詳細については、この journaldev の記事を参照してください。
sourcemaking および journaldev の記事との主な違い:
素人の言葉で、
戦略パターンでは、状態がないか、すべての状態が同じです。さまざまな医師が同じ状態の同じ患者の同じ病気を異なる方法で治療するなど、タスクを実行するさまざまな方法があります。
状態パターンでは、主観的に患者の現在の状態(高温または低温など)のような状態があり、それに基づいて次のアクションコース(薬の処方)が決定されます。依存関係を記述する(技術的には構成)。
両方のコード比較に基づいて技術的に理解しようとすると、両者は非常に似ているため、状況の主観性を失う可能性があります。
これはかなり古い質問ですが、それでも、私は同じ答えを探していました。これが私が発見したことです。
状態のパターンでは、Medial Playerの再生ボタンの例を考えてみましょう。プレイすると、プレイが開始され、プレイしていることをコンテキストに認識させます。クライアントは、再生操作を実行するたびに、プレーヤーの現在の状態を確認します。これで、クライアントはコンテキストオブジェクトを介してオブジェクトの状態が再生されていることを認識したため、ポーズオブジェクトのアクションメソッドを呼び出します。クライアントが状態を認識し、どの状態でアクションを実行する必要があるかを自動化できます。
https://www.youtube.com/watch?v=e45RMc76884https://www.tutorialspoint.com/design_pattern/state_pattern.htm
戦略パターンの場合、クラス図の配置は状態パターンと同じです。クライアントは何らかの操作を行うためにこの配置に来ます。これは、異なる状態の代わりに、たとえばパターンに対して実行する必要がある異なる分析など、異なるアルゴリズムが存在することです。ここで、クライアントは、どのようなアルゴリズム(ビジネス定義のカスタムアルゴリズム)を実行するかをコンテキストに伝え、それを実行します。
https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm
どちらもオープンクローズの原則を実装しているため、開発者は状態パターンと新しいアルゴリズムに新しい状態を追加できます。
しかし違いは、オブジェクトの状態に基づいて異なるロジックを実行するために使用される状態パターンである、それらが使用されるものです。そして、戦略の場合には異なるロジック。
両方のパターンは、いくつかの派生クラスを持つ基本クラスに委任されますが、これらの派生クラスがコンテキストクラスへの参照を保持するのはStateパターンのみです。
別の見方をすれば、StrategyパターンはStateパターンの単純なバージョンです。必要に応じて、サブパターン。派生状態がコンテキストへの参照を保持するかどうか(つまり、コンテキストのメソッドを呼び出したいかどうか)は、本当に異なります。
詳細については、Robert C Martin(およびMicah Martin)の本「C#でのアジャイルの原則、パターン、および実践」でこれに答えてください。 ( http://www.Amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258 )
状態は、状態派生クラス内に少し依存関係があります。ある状態は、他の状態がその後に来ることを知っているように。たとえば、あらゆる季節の状態では夏の後に冬が来ます。ショッピングの場合は預金状態の後に配達の状態が来ます。
一方、Strategyにはこれらのような依存関係はありません。ここでは、プログラム/製品タイプに基づいて、あらゆる種類の状態を初期化できます。
違いは http://c2.com/cgi/wiki?StrategyPattern で説明されています。データを分析するための全体的なフレームワーク内でさまざまなアルゴリズムを選択できるようにするために、Strategyパターンを使用しました。これにより、全体的なフレームワークとそのロジックを変更することなく、アルゴリズムを追加できます。
典型的な例は、関数を最適化するためのフレームワークがあることです。フレームワークは、データとパラメーターを設定します。戦略パターンを使用すると、フレームワークを変更せずに、ステッペスト降下、共役勾配、BFGSなどのアルゴリズムを選択できます。
戦略パターンと状態パターンの構造は同じです。両方のパターンのUMLクラス図を見ると、まったく同じに見えますが、その意図はまったく異なります。状態設計パターンはオブジェクトの状態を定義および管理するために使用され、戦略パターンは交換可能なアルゴリズムのセットを定義するために使用され、クライアントはそれらのいずれかを選択できます。そのため、戦略パターンはクライアント駆動型のパターンであり、オブジェクトは状態自体を管理できます。
要するに、戦略パターンでは、動作中にいくつかの動作を設定でき、状態パターンでは、オブジェクトの状態が変化すると動作が内部的に変化することを確認できます。
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のアルゴリズムの異なる組み合わせでより多くの状態を持つことができます。状態パターンを使用すると、ある状態から別の状態に切り替えて、アルゴリズムの異なる組み合わせを実行できます。