Javaにおける責任のデザインパターンの連鎖
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に乗って]を見つけることができます。