行为型模式之责任链模式(Chain of Responsibility)

本文深入探讨了责任链模式的概念、实现原理及应用场景,通过具体代码示例展示了如何利用责任链模式实现可插拔的处理方式,增强系统的灵活性和可维护性。文章还讨论了责任链模式与其他模式的结合使用,以及在实际开发中的应用价值。

责任链模式的思想是在建立“一条处理链”,使得链上的所有处理者都有机会进行处理


责任链在内存中的形态是一层层的线程调用栈帧(线程frame存储在线程栈stack内),看上去就像一根常常的链条,通常并不知道链条上有多少个环(处理者),每个处理者负责的事情(责任)不同,他们自行判断是否可以处理,如果可以处理则自己处理(不传递到下一个),如果自己不能处理则传递给下一个处理者。

责任链模式的实现通常有一个抽象类,他模板化了处理机制(即:检查是否可以处理、可以则自己处理、不可以则传递给下一个、如果下一个为空则抛出异常等)

PS:责任链上一次都应该只有一个处理者能够处理,而不是每个处理者都依次处理一遍,当然这个没有技术要求,我们完全可以使用其变体实现多处理者处理、过滤器等效果。


责任链只是给他们处理的机会而已,而具体的处理者是否需要处理或是否有能力进行处理都由处理者自己控制,并且,自主控制是否传递到下一个链进行处理


责任链模式使请求与对请求的处理松耦合,使得添加新的处理以及定制处理次序变简单清晰。

使用责任链模式可方便地实现可插拔的处理方式,另外,通过控制处理的过程,如在传递到下个处理器之前和之后作处理,可以实现请求前后的细粒度的控制

可以将责任链模式与“模板方法模式”结合使用以约束将一个请求沿着处理链进行处理


场景:web英语的请求处理过程中,对一个请求的处理包括:记录日志、协议处理、Servlet分发等等,也可以自定义新的处理器,

即处理方式是可插拔的,是用责任链模式非常合适。


设计:

示例代码:

package netty_ws;

interface HandlerChain {
    void setNext(HandlerChain next);
    HandlerChain getNext();

    /**
     * 这里可以 添加 处理需要的参数,如请求上下文:RequestContext
     *
     * void invoke(RequestContext rc);
     *
     */
    void invoke();
}
// 使用模板方法模式
abstract class AbstractHandlerChain implements HandlerChain {
    private HandlerChain next;

    public void setNext(HandlerChain next) {
        this.next = next;
    }
    public HandlerChain getNext() {
        return this.next;
    }
    public void invoke() {
        invokeMe();

        // 可添加 前置处理

        // 传递到下一个处理者
        if (getNext() != null) {
            getNext().invoke();
        }

        // 可添加 后置处理
    }
    // 需要子类实现
    protected abstract void invokeMe();
}
class ProtocolHandler extends AbstractHandlerChain {
    @Override
    protected void invokeMe() {
        System.out.println("处理协议...");
    }
}
class Logger extends AbstractHandlerChain {
    @Override
    protected void invokeMe() {
        if (new java.util.Random().nextBoolean()) {// todo: 自主判断是否需要记录日志
            System.out.println("需要记录日志,记录日志...");
        } else {
            System.out.println("不需要记录日志。");
        }
    }
}
class Dispatcher extends AbstractHandlerChain {
    @Override
    protected void invokeMe() {
        System.out.println("分派相应的Servlet处理...");
    }
}

/**
 * 测试:责任链
 */
public class Test {
    public static void main(String[] args) {
        HandlerChain protocolHandler = new ProtocolHandler();
        HandlerChain logger = new Logger();
        HandlerChain dispatcher = new Dispatcher();

        /**
         * 设置“链”上的处理次序,即:组装出一个“处理链”
         */
        protocolHandler.setNext(logger);
        logger.setNext(dispatcher);

        /**
         * 执行 第一个“链”,后面的链会自动被调用处理。
         */
        protocolHandler.invoke();
    }
}
输出:

处理协议...
需要记录日志,记录日志...
分派相应的Servlet处理...

PS:其实这并不是一个很合适的责任链模式代码示例,更像一个过滤器链,技术没有绝对,能解决问题就好,不过为了增加代码的可读性与可维护性,依然建议遵守不成文的“模式规定”。

<think>我们正在讨论责任链模式Chain of Responsibility)。根据引用[1],责任链模式是一种行为设计模式,它通过将请求沿着处理者链传递来避免请求发送者和接收者之间的耦合。多个处理者对象都有机会处理请求,直到其中一个处理它为止。 引用[2]提供了一段示例代码,展示了责任链模式的实现方式。代码中定义了一个处理者基类CHandler,它包含一个指向下一个处理者的指针(m_pHandler)和一个处理请求的虚函数HandleRequest。然后定义了三个具体的处理者类(CConcreteHandler1, CConcreteHandler2, CConcreteHandler3),每个具体处理者根据自己的条件决定是否处理请求,如果不处理则传递给下一个处理者。 因此,我们可以这样介绍责任链模式责任链模式Chain of Responsibility)是一种行为设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理它为止。这种模式解耦了请求的发送者和接收者,允许多个对象都有机会处理请求。 责任链模式的主要组成部分: 1. 处理者(Handler):定义一个处理请求的接口,通常包含一个指向下一个处理者的引用(后继者链接)。在示例代码中,CHandler就是抽象处理者。 2. 具体处理者(Concrete Handler):实现处理请求的具体逻辑。如果自己能够处理请求,则处理;否则将请求传递给后继者。示例代码中的CConcreteHandler1、CConcreteHandler2、CConcreteHandler3就是具体处理者。 责任链模式的特点: - 降低了对象之间的耦合度:请求发送者无需知道哪个对象会处理其请求。 - 增强了系统的可扩展性:可以动态地增加或修改处理者链。 - 增强了给对象指派职责的灵活性:通过改变链内的成员或者调整次序,可以动态地改变处理流程。 - 责任链简化了对象之间的连接:每个处理者只需保持一个指向其后继者的引用,而不需保持所有处理者的引用。 - 责任分担:每个处理者只需处理自己能够处理的请求,将不能处理的请求传递给下一个处理者,符合类的单一职责原则。 但是,责任链模式也有缺点: - 不能保证请求一定被处理:如果链中没有合适的处理者,请求可能到达链的末端也没有被处理。 - 对于较长的责任链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。 - 调试时可能比较复杂,特别是链条较长时,逻辑可能不易追踪。 应用场景: 责任链模式适用于以下情况: - 有多个对象可以处理同一个请求,具体哪个对象处理该请求在运行时自动确定。 - 需要动态指定一组对象处理请求,或者需要动态添加、删除处理者。 - 在不明确指定接收者的情况下,向多个对象中的一个提交请求。 下面我们用一段标准化的代码示例(使用C++)来展示责任链模式: ```cpp #include <iostream> // 抽象处理者 class Handler { public: virtual ~Handler() {} void SetNext(Handler* next) { next_ = next; } virtual void HandleRequest(int request) const = 0; protected: Handler* next_ = nullptr; }; // 具体处理者A class ConcreteHandlerA : public Handler { public: void HandleRequest(int request) const override { if (request < 10) { std::cout << "ConcreteHandlerA handled request " << request << "\n"; } else if (next_ != nullptr) { next_->HandleRequest(request); } } }; // 具体处理者B class ConcreteHandlerB : public Handler { public: void HandleRequest(int request) const override { if (request >= 10 && request < 20) { std::cout << "ConcreteHandlerB handled request " << request << "\n"; } else if (next_ != nullptr) { next_->HandleRequest(request); } } }; // 具体处理者C class ConcreteHandlerC : public Handler { public: void HandleRequest(int request) const override { if (request >= 20) { std::cout << "ConcreteHandlerC handled request " << request << "\n"; } else if (next_ != nullptr) { next_->HandleRequest(request); } } }; // 客户端代码 int main() { ConcreteHandlerA handlerA; ConcreteHandlerB handlerB; ConcreteHandlerC handlerC; handlerA.SetNext(&handlerB); handlerB.SetNext(&handlerC); // 创建一系列请求 int requests[] = {5, 15, 25}; for (int req : requests) { handlerA.HandleRequest(req); } return 0; } ``` 在这个示例中,我们创建了三个具体处理者(ConcreteHandlerA、ConcreteHandlerB、ConcreteHandlerC),它们分别处理不同范围的请求。客户端将请求发送给链中的第一个处理者(handlerA),然后请求沿着链传递直到被处理。 责任链模式在现实中的应用包括: - 事件处理系统(如GUI中的事件冒泡) - 日志记录器(不同级别的日志由不同的记录器处理) - Web框架中的中间件(每个中间件可以处理请求并决定是否传递给下一个) - 异常处理(try-catch块可以看作是一个责任链) 相关问题: 1. 责任链模式在哪些实际框架或库中有应用? 2. 如何处理责任链中请求未被处理的情况? 3. 责任链模式和状态模式有什么区别? 4. 如何动态地修改责任链的结构? </think>### 责任链模式Chain of Responsibility)介绍 责任链模式Chain of Responsibility)是一种**行为型设计模式**,核心思想是将多个处理对象连接成一条链,请求沿链传递直至被处理。这种模式解耦了请求发送者和接收者,允许多个对象都有机会处理请求。以下是详细解析: --- #### 一、核心结构与原理 1. **处理者(Handler)抽象类** 定义处理请求的接口,包含: - 指向下一个处理者的引用(`m_pHandler`) - 处理请求的虚方法(`HandleRequest()`) ```cpp class Handler { public: void SetNext(Handler* next) { m_pNext = next; } virtual void HandleRequest(int request) = 0; protected: Handler* m_pNext = nullptr; // 后继处理者 }; ``` 2. **具体处理者(Concrete Handler)** 实现具体的处理逻辑,若无法处理则转发给下一个处理者: ```cpp class ConcreteHandlerA : public Handler { public: void HandleRequest(int request) override { if (request < 10) std::cout << "HandlerA processed request: " << request << "\n"; else if (m_pNext) m_pNext->HandleRequest(request); // 传递给下一个 } }; ``` 3. **客户端调用** 构建处理链并发送请求: ```cpp int main() { Handler* handlerA = new ConcreteHandlerA(); Handler* handlerB = new ConcreteHandlerB(); handlerA->SetNext(handlerB); // 设置责任链 handlerA->HandleRequest(15); // 请求在链上传递 } ``` --- #### 二、关键特性 1. **解耦性** 请求发送者无需知道具体处理者,只需向链首提交请求[^1]。 2. **动态扩展** 可随时增减或调整处理者节点(如添加 `ConcreteHandlerC`)。 3. **处理灵活性** 请求可能被链中任意节点处理,也可能未被任何节点处理。 4. **符合开闭原则** 新增处理者无需修改现有代码。 --- #### 三、适用场景 1. **多级请求处理** 如审批流程(员工→经理→CEO)、日志级别过滤(DEBUG→INFO→ERROR)。 2. **动态指定处理对象** 例如中间件管道(如Express.js的中间件链)。 3. **未知接收者的场景** 如GUI事件冒泡机制(控件→父容器→窗口)。 --- #### 四、优缺点分析 | **优点** | **缺点** | |-----------------------------------|--------------------------| | 降低耦合度(请求发送者与接收者分离) | 请求可能未被处理(链尾无兜底) | | 动态增删处理节点 | 长链可能影响性能 | | 简化对象间连接(单向链式传递) | 调试复杂度较高 | --- #### 五、与其他模式的关系 - **与装饰器模式** 两者都基于链式结构,但装饰器模式重在**增强功能**,责任链重在**分发请求**。 - **与状态模式** 状态模式通过状态转移改变行为,责任链通过固定链条传递请求。 --- ### 相关问题 1. 责任链模式如何处理请求未被任何节点处理的情况? 2. 在实际框架(如Spring、Express.js)中责任链模式有哪些典型应用? 3. 如何在责任链模式中实现请求的优先级处理? 4. 责任链模式与命令模式结合会产生什么效果? [^1]: 责任链模式通过对象链解耦请求发送者和接收者[^1]。 [^2]: 具体处理者通过条件判断决定是否处理请求[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值