责任链模式 VS case语句

3
当我阅读责任链模式时,它谈到了将客户端与实际数据处理分离。因此,它说客户端程序调用链的第一个成员,该成员确定是否可以处理请求,如果可以,则处理请求,如果不能,则调用链的下一个成员,以此类推。
我已经阅读过一些额外的成员可以添加到链中,并且客户端程序不必实际更改来处理它的内容。但是,我在示例中看到的情况(包括维基百科)是客户端必须实例化链中的每个成员,甚至为链中的每个成员设置后继者。
当链中对象的顺序由客户端确定且客户端甚至必须实例化链中的每个对象时,这如何被认为是松散耦合呢?

如果您能提供代码示例,其中使用了case语句,您认为它等价于责任链模式,那么回答将更容易些。 - plalx
switch(planet) { case Mercury: PlanetHandler mercuryHandler = new MercuryHandler(); break; case Venus: PlanetHandler venusHandler = new VenusHandler();; break; // etc... } - user3393354
为什么我会选择使用责任链而不是switch语句? - jaco0646
1个回答

3

责任链模式比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);
        // 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 块无法提供相同的灵活性。

1
听起来你看的例子可能并没有实现 GoF 的责任链模式。 - jaco0646
我看了很多,它们都是用同样的方式做的。这里有一个例子http://www.joezimjs.com/javascript/javascript-design-patterns-chain-of-responsibility/。 - user3393354
http://www.journaldev.com/1617/chain-of-responsibility-design-pattern-in-java-example-tutorial - user3393354
http://www.oodesign.com/chain-of-responsibility-pattern.html - user3393354
1
@TahaYavuzBodur,示例已添加。 - jaco0646
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接