当我读到责任链时,它谈到了将客户端与数据的实际处理分开。所以它说客户端程序调用链的第一个成员,该成员确定它是否可以处理请求,如果可以,则处理它,如果不能,则调用链的下一个成员,依此类推。
我已经读过可以将其他成员添加到链中,并且客户端程序不必实际更改即可处理。我在包括 Wikipedia 在内的示例中看到的是,客户端必须实例化链的每个成员,甚至为链的每个成员设置后继。
当链中对象的顺序由客户端确定并且客户端甚至必须实例化链中的每个对象时,这如何被认为是松散耦合?
当我读到责任链时,它谈到了将客户端与数据的实际处理分开。所以它说客户端程序调用链的第一个成员,该成员确定它是否可以处理请求,如果可以,则处理它,如果不能,则调用链的下一个成员,依此类推。
我已经读过可以将其他成员添加到链中,并且客户端程序不必实际更改即可处理。我在包括 Wikipedia 在内的示例中看到的是,客户端必须实例化链的每个成员,甚至为链的每个成员设置后继。
当链中对象的顺序由客户端确定并且客户端甚至必须实例化链中的每个对象时,这如何被认为是松散耦合?
责任链比案例陈述灵活得多。重要的是,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);
// 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 块不会提供相同的灵活性。