責任の連鎖は、ケース ステートメントよりもはるかに柔軟です。重要なことに、CoR は次のことができます。
ハンドラーの関係と優先順位、または要求からハンドラーへのマッピングを配線することなく、要求を処理します。
つまり、クライアントは後続のハンドラーを認識せず、チェーンの存在さえも認識しません。
ハンドラー オブジェクトの数と種類はアプリオリにはわかりませんが、動的に構成できます。
つまり、実行時に新しいハンドラーを追加でき、既存のハンドラーを並べ替えることができます。
より基本的な答えは、case ステートメントは手続き型の構造であるため、Gang of Four 設計パターンなどのオブジェクト指向プログラミングでは一般的に使用されないというものです。
オンラインの例では、簡単にするためにクライアント内で CoR を構成する傾向があります。しかし実際には、それはパターンの目的に反するため、CoR は別の場所に設定されます。おもちゃの例は、チェーンがどのように見えるか、インスタンス化後にどのように動作するかを示すことを目的としています。しかし、それがインスタンス化される場所は、CoR を選択する動機の鍵となります。
例: クライアントはサービスに依存して String 値を処理します。
サービス API は自明です。
interface StringHandler {
void handle(String arg);
}
クライアントは無限に複雑かもしれませんが、ある時点でサービスを呼び出します。
class Client {
private final StringHandler argHandler;
Client(StringHandler argHandler) {
this.argHandler = argHandler;
}
void method(String arg) {
argHandler.handle(arg);
// more business logic...
}
}
当社は、一連の責任としてサービスを実装することを選択します。
class ChainedHandler implements StringHandler {
private final String handledString;
private ChainedHandler next;
ChainedHandler(String handledString) {
this.handledString = handledString;
}
Optional<ChainedHandler> next() {
return Optional.ofNullable(next);
}
ChainedHandler next(ChainedHandler handler) {
ChainedHandler subsequent = next;
next = handler;
if (handler != null && subsequent != null)
handler.next(subsequent);
return this;
}
@Override
public void handle(String arg) {
if (arg.equalsIgnoreCase(handledString)) {
System.out.println("Handled: " + arg);
} else {
next().ifPresentOrElse(
handler -> handler.handle(arg),
() -> System.out.println("No handler for: " + arg));
}
}
}
そのため、チェーンを構築し、それをクライアントに接続し、チェーンを変更していくつかのシナリオを実行します。
public static void main(String... commandLineArgs) {
List<String> args = commandLineArgs.length > 0
? Arrays.asList(commandLineArgs)
: List.of("foo", "bar", "baz", "qux");
ChainedHandler chain = new ChainedHandler("foo")
.next(new ChainedHandler("bar")
.next(new ChainedHandler("baz")));
Client client = new Client(chain);
args.forEach(client::method);
System.out.println();
chain.next(new ChainedHandler("qux"));
args.forEach(client::method);
System.out.println();
chain.next(null);
args.forEach(client::method);
}
Client
はチェーンの存在を認識していないことに注意してください。さらに、コードを編集せずにチェーンを変更することに注意してください。これは、GoF が参照するデカップリングです。case ステートメントまたは if/else ブロックは、同じ柔軟性を提供しません。