责任链模式比case语句灵活得多。重要的是,CoR可以:
处理请求而无需硬编码处理程序关系、优先级或请求到处理程序的映射。
这意味着客户端不知道任何后续处理程序,甚至不知道链的存在。
处理对象的数量和类型不是预先确定的,可以动态配置。
这意味着可以在运行时添加新的处理程序,并重新排序现有的处理程序。
更基本的答案是,case语句是一种过程式构造,在面向对象编程(如四人组设计模式)中通常不使用。
在线示例可能倾向于在客户端内部配置CoR以简化操作;但在实践中,这违背了模式的目的,因此应该在其他地方配置CoR。玩具示例只是为了展示链的外观和实例化后的操作方式;但是,实例化的位置是选择CoR的动机所在。
例子:客户端依赖于一个服务来处理字符串值。
服务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);
}
}
我们选择将服务实现为责任链模式。
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 块无法提供相同的灵活性。