概念
責任の連鎖パターン(責任の連鎖パターン)は、チェーン内の各ノードをオブジェクトとして扱い、各ノードは異なる要求を処理し、次のノードオブジェクトを内部的に維持します。チェーンの最初のセグメントからリクエストが送信されると、オブジェクトがリクエストを処理するまで、チェーンのパスに沿って各ノードオブジェクトに順番に渡されます。このタイプの設計パターンは行動パターンです。
責任の連鎖モデルには、主に2つの役割が含まれます。
- 抽象ハンドラー(ハンドル):処理メソッドを定義し、次の処理ノードのハンドルオブジェクトへの参照を維持します。
- コンクリートハンドル(ConcreteHandle):リクエストを処理し、関心がない場合は転送します。
成し遂げる
次に、例としてログイン検証を取り上げます
1.抽象ハンドラーを作成します
public abstract class Handle {
protected Handle chain;
public void next(Handle handle){
this.chain=handle;
}
public abstract void doHandle(Member member);
}
2.特定のプロセッサ
public class ValidateHadle extends Handle {
@Override
public void doHandle(Member member) {
if("".equals(member.getName())||"".equals(member.getPwd())){
System.out.println("用户名或密码为空");
return;
}
System.out.println("用户名密码格式校验完毕");
chain.doHandle(member);
}
}
public class LoginHandle extends Handle {
@Override
public void doHandle(Member member) {
System.out.println("登陆成功");
chain.doHandle(member);
}
}
public class AuthHandle extends Handle {
@Override
public void doHandle(Member member) {
System.out.println("欢迎管理员!");
}
}
3.テスト
public class ChainTest {
public static void main(String[] args) {
Handle validateHandle=new ValidateHadle();
Handle loginHandle=new LoginHandle();
Handle authHandle=new AuthHandle();
validateHandle.next(loginHandle);
loginHandle.next(authHandle);
validateHandle.doHandle(new Member("tom","123"));
}
}
動作結果:
使用するシーン
- オブジェクトごとに同じリクエストが処理されますが、特定のオブジェクト処理は実行時に動的に決定されます
- 受信者を明確に指定せずに、複数のオブジェクトの1つにリクエストを送信します
- リクエストを処理するオブジェクトのグループを動的に指定できます
SpringFrameworkでのアプリケーション
JDKには、非常に一般的なクラスFilterがあります
public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
public void destroy();
}
このフィルターインターフェイスは非常にシンプルで、責任の連鎖におけるハンドル抽象ロールと同等です。もう一度見てくださいdoFilterFilterChainクラスメソッドの最後のパラメーター
public interface FilterChain {
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
1つだけが定義されていますdoFilter方法、それらはどのように接続してチェーンを形成しますか?SpringのMockFilterChainクラスの実装を見てみましょう
public class MockFilterChain implements FilterChain {
private ServletRequest request;
private ServletResponse response;
private final List<Filter> filters;
private Iterator<Filter> iterator;
public MockFilterChain() {
this.filters = Collections.emptyList();
}
public MockFilterChain(Servlet servlet) {
this.filters = initFilterList(servlet);
}
public MockFilterChain(Servlet servlet, Filter... filters) {
Assert.notNull(filters, "filters cannot be null");
Assert.noNullElements(filters, "filters cannot contain null values");
this.filters = initFilterList(servlet, filters);
}
private static List<Filter> initFilterList(Servlet servlet, Filter... filters) {
Filter[] allFilters = ObjectUtils.addObjectToArray(filters, new ServletFilterProxy(servlet));
return Arrays.asList(allFilters);
}
public ServletRequest getRequest() {
return this.request;
}
public ServletResponse getResponse() {
return this.response;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
Assert.state(this.request == null, "This FilterChain has already been called!");
if (this.iterator == null) {
this.iterator = this.filters.iterator();
}
if (this.iterator.hasNext()) {
Filter nextFilter = this.iterator.next();
nextFilter.doFilter(request, response, this);
}
this.request = request;
this.response = response;
}
}
チェーンのすべてのフィルターをリストに入れてから、doFilterこの方法は、リストを反復することです。つまり、リスト内のフィルターは、
次のようにUMLクラス図を順番に実行します。
総括する
利点
- 要求を処理から切り離します
- オブジェクトを簡略化しました。オブジェクトがチェーン構造を知る必要がないように
- リンク構造は柔軟であり、リンク構造の順序を変更することにより、責任を動的に追加または削除できます。
- 新しいリクエスト処理クラスを簡単に拡張できます
不利益
- 責任の連鎖が長すぎると、処理時間が長くなり、全体的なパフォーマンスに影響を及ぼします。
- ノードオブジェクトに循環参照がある場合、無限ループが発生し、システムがクラッシュします