誰かが責任の連鎖パターンの簡単な説明を提供できますか?wikiの記事は少し紛らわしいと思いました。
6 に答える
非常に良い例は、Java サーブレット フィルターです。これは、HTTP 要求がターゲットに到達する前に実行されるコードの一部です。
- チェーンには複数のインスタンスが含まれ、それぞれが異なるアクションを実行します
- チェーン内の各インスタンスは、次のインスタンスに伝播するか、フローを停止するかを選択できます
したがって、サーブレット フィルターを使用すると、
ユーザーが認証されているかどうかを確認するフィルター。彼がそうである場合、フィルターは次のフィルターに伝播します
次のフィルターは、ユーザーが現在のリソースへのアクセス許可を持っているかどうかを確認します。もしそうなら、それは次に伝播します
次は現在のリクエスト URL とユーザー名をログに記録し、常に次へ伝播します。
チェーンには他に何もないため、ターゲットオブジェクトが最終的に呼び出されます
私はアナロジーの助けを借りて試してみます:
コマンドがホッケーのパックとして処理され、一連の責任ハンドラー クラスが 1 つの穴を持つネットとして処理されると考えてください。ここで、さまざまな半径のこのようなネットが互いに積み重ねられていると想像してください(ネットの上に最小半径の穴があります)。
パックを上から落とします。パックの半径が最初の穴よりも大きい場合、パックは穴に引っかかり、それ以上落ちません。コマンドが最初のハンドラによって処理されたことを意味します。
しかし、パックが穴よりも小さい場合、パックは次の穴に移動し、すべてのネットに引っかかるか落ちるまで続きます。パックが通過するすべてのネット (責任ハンドラー クラス) がパックを処理した (コマンドを処理した)。
このパターンを使用して、リクエストを調べるオブジェクトのチェーンを作成します。それぞれが順番にリクエストを調べ、それを処理するか、チェーン内の次のオブジェクトに渡します。
利点
- リクエストの送信者とその受信者を切り離します
- チェーン構造を認識し、そのメンバーへの参照を保持する必要がないため、オブジェクトが簡素化されます
- チェーンの順序またはメンバーを変更することにより、責任を動的に追加または削除できます
欠点
- リクエストの実行は保証されていません。オブジェクトがリクエストを処理しない場合、リクエストはチェーンから外れる可能性があります
- 実行時の特性は、監視およびデバッグが難しい場合があります
潜在的なユースケース
- マウスクリックとキーボードイベント。
- Eメール。たとえば、電子メールが受信され、最初のハンドラーであるスパムハンドラーに渡されます。次に、処理されるか、2番目のハンドラーに渡されます。
から:
これは、このパターンに関する興味深いInformITの記事で、サンプルコードが含まれています。
理解するための最良の方法は、簡単な例を分析することです。それは彼です:
プログラムは単語を英語から他の言語に翻訳します (非常に単純化されたバージョン:)) 翻訳された単語は後続の辞書に渡されます。辞書はチェーンを形成します。
using System;
// The 'Handler' abstract class
abstract class Handler
{
//chain link
private Handler _successor;
//
static private Handler _first;
public Handler Successor
{
set
{
_successor = value;
}
get
{
return _successor;
}
}
public Handler First
{
set
{
_first = value;
}
get
{
return _first;
}
}
//
public void HandleRequest(string request)
{
if (First == this)
{
Console.WriteLine("\n\tWe translate word => \"{0}\"\n", request);
First.Translator(request);
}
//
if (Successor != null)
{
//Translation by the successor's dictionary
Successor.Translator(request);
//Transfer of word (request) to another chain (dictionary)
Successor.HandleRequest(request);
}
}
//
abstract public void Translator(string word);
}
//The concrete class
class GermanDictionary : Handler
{
override public void Translator(string word)
{
switch (word)
{
case "Job":
word = "Arbeit";
break;
case "Rest":
word = "Rest";
break;
}
Console.WriteLine("\t\tinto German => \"{0}\"", word);
}
}
class FrenchDictionary : Handler
{
override public void Translator(string word)
{
switch (word)
{
case "Job":
word = "Travail";
break;
case "Rest":
word = "Reste";
break;
}
Console.WriteLine("\t\tinto French => \"{0}\"", word);
}
}
class PolishDictionary : Handler
{
override public void Translator(string word)
{
switch (word)
{
case "Job":
word = "Praca";
break;
case "Rest":
word = "Odpoczynek";
break;
}
Console.WriteLine("\t\tinto Polish => \"{0}\"", word);
}
}
////
class Client
{
static void Main()
{
Handler h1 = new FrenchDictionary();
Handler h2 = new GermanDictionary();
Handler h3 = new PolishDictionary();
//Determining the consequences in the chain
h1.First=h1;
h1.Successor=h2;
h2.Successor=h3;
h3.Successor=null;
//The word that is translated
string request = "Job";
//Starting the recursive method.
h1.HandleRequest(request) ;
//Another word is translated.
request = "Rest";
h1.HandleRequest(request);
Console.ReadKey();
}
}
/*output:
We translate word => "Job"
into French => "Travail"
into German => "Arbeit"
into Polish => "Praca"
We translate word => "Rest"
into French => "Reste"
into German => "Rest"
into Polish => "Odpoczynek"
*/