1前書き


2責任の連鎖


Wikipedia

は、一連の責任を「コマンドオブジェクトのソースと一連の処理オブジェクト」からなる設計パターンとして定義しています。

チェーン内の各処理オブジェクトは特定の種類のコマンドを担当し、処理が完了すると、チェーン内の次のプロセッサにコマンドを転送します。

責任の連鎖パターンは次の場合に便利です。


  • コマンドの送信者と受信者を分離する


  • 処理時に処理方針を選ぶ


3例

認証要求を処理するためのチェーンを作成するために、一連の責任を使用します。

そのため、入力認証プロバイダは

command

になり、各認証プロセッサは個別の

processor

オブジェクトになります。

まず、プロセッサ用の抽象基本クラスを作成しましょう。

public abstract class AuthenticationProcessor {

    public AuthenticationProcessor nextProcessor;

   //standard constructors

    public abstract boolean isAuthorized(AuthenticationProvider authProvider);
}

次に、

AuthenticationProcessor

を拡張する具体的なプロセッサを作成しましょう。

public class OAuthProcessor extends AuthenticationProcessor {

    public OAuthProcessor(AuthenticationProcessor nextProcessor) {
        super(nextProcessor);
    }

    @Override
    public boolean isAuthorized(AuthenticationProvider authProvider) {
        if (authProvider instanceof OAuthTokenProvider) {
            return true;
        } else if (nextProcessor != null) {
            return nextProcessor.isAuthorized(authProvider);
        }

        return false;
    }
}

public class UsernamePasswordProcessor extends AuthenticationProcessor {

    public UsernamePasswordProcessor(AuthenticationProcessor nextProcessor) {
        super(nextProcessor);
    }

    @Override
    public boolean isAuthorized(AuthenticationProvider authProvider) {
        if (authProvider instanceof UsernamePasswordProvider) {
            return true;
        } else if (nextProcessor != null) {
            return nextProcessor.isAuthorized(authProvider);
        }

        return false;
    }
}

ここでは、受信した承認要求用に2つの具象プロセッサ

UsernamePasswordProcessor

と__OAuthProcessor.を作成しました。

それぞれに対して、

isAuthorized

メソッドをオーバーライドしました。

それでは、いくつかテストを作成しましょう。

public class ChainOfResponsibilityTest {

    private static AuthenticationProcessor getChainOfAuthProcessor() {
        AuthenticationProcessor oAuthProcessor = new OAuthProcessor(null);
        return new UsernamePasswordProcessor(oAuthProcessor);
    }

    @Test
    public void givenOAuthProvider__whenCheckingAuthorized__thenSuccess() {
        AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor();
        assertTrue(authProcessorChain.isAuthorized(new OAuthTokenProvider()));
    }

    @Test
    public void givenSamlProvider__whenCheckingAuthorized__thenSuccess() {
        AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor();

        assertFalse(authProcessorChain.isAuthorized(new SamlTokenProvider()));
    }
}

上記の例では、一連の認証プロセッサを作成しています。


UsernamePasswordProcessor – > OAuthProcessor

。最初のテストでは認証は成功し、もう一方のテストでは失敗します。

まず、

UsernamePasswordProcessor

が、認証プロバイダが

UsernamePasswordProvider

のインスタンスであるかどうかを確認します。

期待される入力ではないので、

UsernamePasswordProcessor



OAuthProcessor

に委任します。

最後に、

OAuthProcessor

がコマンドを処理します。最初のテストでは、一致があり、テストは成功します。もう1つは、チェーン内にプロセッサがなくなったため、テストが失敗したことです。


4実施原則

責任の連鎖を実行する際には、いくつかの重要な原則を念頭に置く必要があります。

  • ** チェーン内の各プロセッサは、

コマンドを処理する


** 上記の例では、すべてのプロセッサの実装は


isAuthorized



チェーン内のすべてのプロセッサは、次のプロセッサを参照する必要があります。

プロセッサ


** 上記で、

UsernamePasswordProcessor



OAuthProcessor

に委任しています

  • ** 各プロセッサは、次のプロセッサに委任する責任があります。

ドロップされたコマンドに注意してください


** この例でも、コマンドが

SamlProvider

のインスタンスである場合

それから要求は処理されないかもしれないし、許可されないでしょう


プロセッサは再帰的サイクルを形成するべきではありません**

  • ** この例では、チェーンにサイクルはありません。


UsernamePasswordProcessor – > OAuthProcessor.

ただし、明示的に設定した場合

OAuthProcessorの次のプロセッサとして

UsernamePasswordProcessor




チェーンのサイクルが終わる

:

UsernamePasswordProcessor – >
OAuthProcessor – > UsernamePasswordProcessor.

次のプロセッサの採用
コンストラクタ内でこれを助けることができる


チェーン内の1つのプロセッサだけが特定のコマンドを処理します**

  • ** この例では、受信コマンドがのインスタンスを含む場合


OAuthTokenProvider



OAuthProcessor

のみがコマンドを処理します

** 5実世界での使用法

Javaの世界では、私たちは毎日責任の連鎖から恩恵を受けています。

  • そのような古典的な例の1つは、


    Java ** のサーブレットフィルタです。これにより、複数のフィルタでHTTP要求を処理できます。その場合でも、各フィルタは次のフィルタの代わりにチェーンを呼び出します。

サーブレットフィルタでのこのパターンの理解を深めるために、以下のコードスニペットを見てみましょう


:

public class CustomFilter implements Filter {

    public void doFilter(
      ServletRequest request,
      ServletResponse response,
      FilterChain chain)
      throws IOException, ServletException {

       //process the request

       //pass the request (i.e. the command) along the filter chain
        chain.doFilter(request, response);
    }
}

上記のコードスニペットに見られるように、チェーン内の次のプロセッサにリクエストを渡すために

FilterChain

‘s

doFilter

メソッドを呼び出す必要があります。


6. デメリット

そして、一連の責任がどれほど興味深いのかを見てきたので、次にいくつかの欠点を覚えておきましょう。


  • **

  • パフォーマンスに影響を与える可能性がある、深いスタックトレースを作成する可能性があります。

**


7. 結論

この記事では、着信認証要求を承認するためのチェーンを使用して、一連の責任とその長所と短所について説明しました。

そして、いつものように、ソースコードはhttps://github.com/eugenp/tutorials/tree/master/patterns/design-patterns/[GitHubに乗って]を見つけることができます。