はじめに:責任連鎖モデルは、例外のキャプチャと処理に非常に似ています。問題が発生すると、現在のオブジェクトはそれを処理できるかどうかを確認し、処理できない場合は、問題を上司にスローして処理します。 、ただしこれに注意してください。の上位は、例外処理とは異なり、必ずしも継承関係の親クラスを参照しているわけではありません。したがって、問題が解決できない場合は、別のオブジェクトに引き渡されて処理され、現在のオブジェクトがオフラインで見つからなくなるまで渡されて処理が終了すると言えます。下の図に示すように、同じレベルのクラスはSupportクラスを継承します。現在のオブジェクトを処理できない場合、事前に設定された転送関係に従って問題が次の人に引き継がれます。 「給水塔の近くが最初に月を迎える」ということは、能力次第です。また、誰もがなぞなぞを渡して答えを推測し、座席と所定の順序で渡すという小さなゲームをプレイしていることがわかります.1人が答えることができればゲームは終了し、そうでなければ誰もが答えるとゲームは終了します出なければ終了します。これは、同じレベルの概念を反映した、責任の連鎖の本質である可能性があります。
1.関連記事の推奨事項
- Linuxカーネル-赤黒木のC ++実装(ソースコードを含む)
- Linuxカーネル-赤黒木の原理とアルゴリズムの詳細な紹介(コードデモンストレーションを含む)
- データ構造とアルゴリズム-文字列から数値へのハッシュ関数とブルームフィルター
- データアーキテクチャとアルゴリズム-BツリーとB +の原理とアルゴリズムの詳細な紹介(図を含み、理解しやすい)
- Linuxのデザインパターン-StrategyPattern(StrategyPattern)は、簡単な言葉で説明しています[初心者のコレクションに推奨]
- Linuxでのデザインパターン-デリゲートパターン(デリゲートパターン)を簡単に説明[初心者コレクションに推奨]
2.責任連鎖モデルを実現する3つの方法
責任チェーンモードの定義:複数のオブジェクトがリクエストを処理する機会を持てるようにすることで、リクエストの送信者と受信者の間の結合関係を回避し、このオブジェクトをチェーンに接続し、このチェーンに沿ってリクエストを渡しますこれまでに1つのオブジェクトが彼を扱うまで。ここでは、責任連鎖モデルとは何かをあまり紹介せず、主にJavaでの記述方法について説明します。
主に次の3つのフレームワークのコードから導入されました。
- サーブレットでフィルタリングする
- ダボのフィルター
- mybatisのプラグインの3つのフレームワークには、責任の連鎖を実装するさまざまな方法があります。
1.サーブレットのフィルタ
サーブレットは、FilterおよびFilterChainインターフェースをそれぞれ定義します。コア・コードは次のとおりです。
public final class ApplicationFilterChain implements FilterChain {
private int pos = 0; //当前执行filter的offset
private int n; //当前filter的数量
private ApplicationFilterConfig[] filters; //filter配置类,通过getFilter()方法获取Filter
private Servlet servlet
@Override
public void doFilter(ServletRequest request, ServletResponse response) {
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = filterConfig.getFilter();
filter.doFilter(request, response, this);
} else {
// filter都处理完毕后,执行servlet
servlet.service(request, response);
}
}
}
コードはかなり単純で、構造は比較的明確です。実際のサーブレットを呼び出す前にさまざまなフィルタロジックを実行するために、フィルタリストとサーブレットを含むチェーンを定義します。
2.ダボでフィルタリング
Dubboは、Filterを作成するときの別の方法です。これは、FilterをInvokerの匿名クラスにカプセル化し、リンクリストなどのデータ構造を使用することで、責任の連鎖を完了します。コアコードは次のとおりです。
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//只获取满足条件的Filter
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
...
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
...
};
}
}
return last;
}
Dubboの責任チェーンにはFilterChainのようなクラスはありません。FilterはInvokerの呼び出しと組み合わされます。代わりに、リンクリストが作成されます。呼び出すとき、最初のノードのみがわかり、各ノードには次に呼び出されるノードの情報が含まれます。Invokerは、Filterが表示しない指定されたnextをカプセル化しますが、Java匿名クラスとfinalのメカニズムを通じて同じ効果が得られます。
3.Mybatisのプラグイン
Mybatisは、公式に提供されているか、独自に定義されているかに関係なく、さまざまなプラグインを構成できます。プラグインはフィルターに似ており、SQLステートメントの実行時にいくつかの操作を実行します。Mybatisの責任の連鎖は、プラグインを使用して実際のExecutorクラスをプロキシする動的プロキシを介して行われます。(プラグインはプロキシをネストできるため、ここでは結合モードが実際に使用されます)、コアコードは次のとおりです。
public class Plugin implements InvocationHandler{
private Object target;
private Interceptor interceptor;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (满足代理条件) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
}
//对传入的对象进行代理,可能是实际的Executor类,也可能是Plugin代理类
public static Object wrap(Object target, Interceptor interceptor) {
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
}
簡単な概略図は次のとおりです
。これは、責任チェーンモデルでのサーブレット、ダボ、およびMybatisのさまざまな実装方法の簡単な紹介です。サーブレットは比較的明確で実装が簡単ですが、ダボとMybatisは責任ベースの増加に適しています。元のコードで。チェーンモードコードの変更が最も少ない。
2、コードのデモンストレーション
トラブルクラス:(データ構造)
1 package zyr.dp.cor;
2
3 public class Trouble {
4
5 private int number;
6 public Trouble( int number){
7 this.number=number;
8 }
9 public int getNumber() {
10 return number;
11 }
12 public String toString(){
13 return "问题编号:["+number+"]";
14 }
15 }
サポートクラス:(抽象クラス、テンプレートメソッドが使用されます)
package zyr.dp.cor;
public abstract class Support {
protected abstract boolean resolve(Trouble trouble);
String name;
Support next;
public Support(String name){
this.name=name;
}
public String toString() {
return "对象:<"+name+">";
}
public Support setAndReturnNext(Support next){
this.next=next;
return next;
}
public final void support(Trouble trouble){
if(resolve(trouble)){
done(trouble);
}else if(next!=null){
next.support(trouble);
}else{
fail(trouble);
}
}
protected void fail(Trouble trouble) {
System.out.println(this+"解决问题失败,"+trouble);
}
protected void done(Trouble trouble) {
System.out.println(this+"已经解决问题,"+trouble);
}
}
NoSupportクラス:
1 package zyr.dp.cor;
2
3 public class NoSupport extends Support {
4
5 public NoSupport(String name) {
6 super(name);
7 }
8
9 protected boolean resolve(Trouble trouble) {
10 return false;
11 }
12
13 }
OddSupportクラス:
package zyr.dp.cor;
2
3 public class OddSupport extends Support {
4
5 public OddSupport(String name) {
6 super(name);
7 }
8
9 protected boolean resolve(Trouble trouble) {
10 return (trouble.getNumber()%2) == 1 ? true : false;
11 }
12
13 }
SpecialSupportクラス:
package zyr.dp.cor;
2
3 public class SpecialSupport extends Support {
4
5 public int specialNumber;
6 public SpecialSupport(String name,int specialNumber) {
7 super(name);
8 this.specialNumber= specialNumber;
9 }
10
11 protected boolean resolve(Trouble trouble) {
12 return trouble.getNumber()==specialNumber ? true : false;
13 }
14
15 }
LimitSupportクラス:
package zyr.dp.cor;
2
3 public class LimitSupport extends Support {
4
5 private int limit;
6 public LimitSupport(String name,int limit) {
7 super(name);
8 this.limit=limit;
9 }
10
11 protected boolean resolve(Trouble trouble) {
12 return trouble.getNumber()<=limit? true : false;
13 }
14
15 }
メインクラス:
package zyr.dp.cor;
2
3 public class Main {
4
5 public static void main(String[] args) {
6 Support limitSupportLess = new LimitSupport("有限支持小",5);
7 Support limitSupportMore = new LimitSupport("有限支持大",15);
8 Support oddSupport = new OddSupport("奇数支持");
9 Support specialSupport = new SpecialSupport("特定支持",36);
10 Support noSupport = new NoSupport("没有支持");
11 limitSupportLess.setAndReturnNext(limitSupportMore).setAndReturnNext(oddSupport).setAndReturnNext(specialSupport).setAndReturnNext(noSupport);
12 System.out.println("===<有限支持小>尝试解决问题===");
13 for(int i=0;i<40;i++){
14 limitSupportLess.support(new Trouble(i));
15 }
16 System.out.println("===<特定支持>尝试解决问题===");
17 for(int i=0;i<40;i++){
18 specialSupport.support(new Trouble(i));
19 }
20
21 }
22
23 }
演算結果:
同じレベルのオブジェクトを見て、追加された順に並べることができます。これは非常に重要です。実際のアプリケーションでは、常に応答能力の最も弱いクラスを最初に配置し、次にそれを少し強化します。これは回答能力の弱いクラスが回答する機会を与えます。例のように、回答能力の高いクラスが直接問題に対処できる場合、次のクラスに戻されません。もちろん、いくつかのクラスも見られます。その中のクラス。機能が制限されており、一部のクラスは他のクラスの機能と重複しています。もちろん、すべてのクラスで解決できない問題もあります。
責任の連鎖を通じて、問題を問題の対象から分離することができます。これは、問題が何であるかがわからない(選択肢が多い)が、対処する必要がある(対応する処理を設計する)状況に特に適しています。選択ごとのクラス))、これは質問を要求する人と質問に答える人との関係を弱めます。要求を行う人が要求を処理する人を知っている必要がある場合、コードの再利用を助長しません。リクエストのオブジェクト内にある必要がありますリクエストを処理するオブジェクトを呼び出し、責任の連鎖モデルを使用すると、これをうまく回避できるため、コードのこの部分を分離して、原則に準拠するコンポーネントとして使用できます。開閉の。
同様に、テンプレートメソッドが責任の連鎖で使用され、処理されるプロセスが親クラスで抽象的に定義されていることがわかります。これにより、展開と変更が非常に便利になります。委任のアイデアを使用することは非常に良いアイデアですが、今回は、実際にはリンクリストである責任の連鎖を通じて、問題に対処するために自分自身を使用することは非常に良いアイデアです。責任チェーンは動的に変更できると同時に、各責任チェーン内のオブジェクトはそれぞれの問題に焦点を当てることができます。この考え方は明確で拡張が容易ですが、責任チェーンモードが使用されるのは、特定の問題の処理は継続的に呼び出されます(リンクリストのトラバース))誰がそれを処理するのかを直接知る方法と比較すると、間違いなく遅延が発生し、トレードオフが必要になります。
最後に、resolve()属性が保護されていることに注意してください。そうすることの利点は、同じパッケージまたはサブクラスがこのメソッドを使用できることですが、他のパッケージクラスは使用できません。これは、問題を解決するメソッドがサブクラスClassを使用する必要があるためです。メソッドが誤用されないようにします。失敗メソッドと成功メソッドをprotectedに設定すると、サブクラスが継承および変更できるようになり、他のパッケージのクラスが使用できないようになります。support()メソッドの場合、他のパッケージで使用できます。したがって、publicを使用しても問題ありません。コードの記述の厳密さを参照してください。
4、まとめ
責任チェーンは、テンプレートメソッドと委任のアイデアを使用してリンクリストを構築します。リンクリストをトラバースすることにより、リンクリスト内の各ノードは何かを処理できる人に1つずつ尋ねられます。ノードが有能である場合、それは直接処理されない場合は、下向きに続行されます。パス、next == nullのいずれも処理できない場合、処理は終了します。責任の連鎖は処理の遅延を引き起こしますが、それはスケーラビリティを切り離して改善し、処理メソッドクラスを自分の業務の処理により集中させ、拡張を容易にし、処理の優先順位を変更します。また、アプリケーションも非常に広いです。
何を待っていますか?linuxC / C ++言語交換グループをお勧めします:[ 1106675687 ]グループファイルで共有したほうがよいと思う学習本とビデオ資料をいくつかまとめました。必要に応じて追加できます。トップ100がグループに入り、C / C ++の追加コピー、199に相当するLinux資料(ビデオチュートリアル、電子書籍、実際の戦闘プロジェクトおよびコード)が配布され、次の部分が表示されます。