design-patterns - 责任链 VS 案例陈述

标签 design-patterns switch-statement loose-coupling chain-of-responsibility

当我读到责任链时,它谈到将客户端与数据的实际处理分开。 所以它说客户端程序调用链的第一个成员,该成员确定它是否可以处理请求,如果可以,它会处理请求,如果不能,则调用链的下一个成员,依此类推。

我读到可以将额外的成员添加到链中,客户端程序不必实际更改来处理它。 我在示例(包括维基百科)中看到的是,客户端必须实例化链中的每个成员,甚至为链中的每个成员设置后继者。

当链中对象的顺序由客户端确定并且客户端甚至必须实例化链中的每个对象时,这如何被视为松散耦合?

最佳答案

Chain of Responsibility比 case 语句灵活得多。重要的是,CoR 可以:

process the requests without hard-wiring handler relationships and precedence, or request-to-handler mappings.

这意味着客户端不知道任何后续处理程序,甚至不知道链的存在。

The number and type of handler objects isn't known a priori, they can be configured dynamically.

意味着可以在运行时添加新的处理程序,并且可以重新排序现有的处理程序。

一个更基本的答案是 case 语句是 procedural构造,因此通常不用于面向对象的编程,例如四人组设计模式。

为了简单起见,在线示例可能倾向于在客户端中配置 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));
        }
    }
}

因此我们构建了一个 Chain,将其连接到 Client,并通过修改 Chain 来执行一些场景。

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 block 不会提供相同的灵 active 。

关于design-patterns - 责任链 VS 案例陈述,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34204740/

相关文章:

flutter/Dart : Communication between features in Clean Architecure

javascript - JavaScript 三元运算符可以支持 3 个条件吗?

java - 是否有一个好的 Java 后端平台/库/框架来保持后端和前端松散耦合?

c++ - 在 dll 边界上公开 std::vector - 编译器独立性的最佳实践

c# - ASP.NET MVC 项目层

node.js - 如何让值对象远离服务器?

C++:如何检查枚举只有唯一值

php - Symfony2 并避免过于冗长的代码

java - 已部署的 Web 应用程序中数据库更改的最佳实践

java - 在 switch 语句中使用 Math.signum(x) 还是 Integer.compare(x, 0) 更好?