我要学会设计模式之责任链模式

533 阅读3分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战


我要学会设计模式之责任链模式

定义:多个对象均有机会处理请求,从而解除发送者和接受者之间的耦合关系。这些对象连接成为“链式结构”,每个节点转发请求,直到有对象处理请求为止。

核心思想:请求者不必知道是谁哪个节点对象处理的请求。如果当前不符合终止条件,那么把请求转发给下一个节点处理。

image-20210809220709733


什么是“责任链模式”?

责任链模式定义:多个对象均有机会处理请求,从而解除发送者和接受者之间的耦合关系。这些对象连接成为“链式结构”,每个节点转发请求,直到有对象处理请求为止。

核心思想就是:请求者不必知道是谁哪个节点对象处理的请求。如果当前不符合终止条件,那么把请求转发给下一个节点处理。

而当需求具有“传递”的性质时(代码中其中一种体现就是:多个if、else if、else if、else嵌套),就可以考虑将每个分支拆分成一个节点对象,拼接成为责任链。


优点与代价

优点:

  • 可以根据需求变动,任意向责任链中添加 / 删除节点对象
  • 没有固定的“开始节点”,可以从任意节点开始

代价:责任链最大的代价就是每个节点带来的多余消耗。当责任链过长,很多节点只有传递的作用,而不是真正地处理逻辑。

什么时候需要用责任链模式?

系统设计的时候,注意区分主次就好,即哪部分是核心流程,哪部分是辅助流程,辅助流程是否有N多if...if...if...的场景,如果是且每个if都有一个统一的抽象,那么抽象辅助流程,把每个if作为一个责任对象进行链式调用,优雅实现,易复用可扩展。


代码实现

为了方便演示,模拟常见的“日志打印”场景。模拟了 3 种级别的日志输出:

  • LogHandler: 普通日志
  • WarnHandler:警告日志
  • ErrorHandler:错误日志

首先我们会构造“责任链”:LogHandler -> WarnHandler -> ErrorHandlerLogHandler作为链的开始节点。

如果是普通日志,那么就由 LogHandler 处理,停止传播;如果是 Warn 级别的日志,那么 LogHandler 就会自动向下传递,WarnHandler 接收到并且处理,停止传播;Error 级别日志同理。

public class Study {
​
    public void study(PreparationList preparationList) {
        if (preparationList.isWashHair()) {
            System.out.println("洗脸");
        }
        if (preparationList.isWashHair()) {
            System.out.println("洗头");
        }
        if (preparationList.isHaveBreakfast()) {
            System.out.println("吃早餐");
        }
​
        System.out.println("我可以去上学了!");
    }
​
}
public abstract class AbstractPrepareFilter {
​
    private AbstractPrepareFilter nextPrepareFilter;
​
    public AbstractPrepareFilter(AbstractPrepareFilter nextPrepareFilter) {
        this.nextPrepareFilter = nextPrepareFilter;
    }
​
    public void doFilter(PreparationList preparationList, Study study) {
        prepare(preparationList);
​
        if (nextPrepareFilter == null) {
            study.study();
        } else {
            nextPrepareFilter.doFilter(preparationList, study);
        }
    }
​
    public abstract void prepare(PreparationList preparationList);
​
}
public class WashFaceFilter extends AbstractPrepareFilter {
​
    public WashFaceFilter(AbstractPrepareFilter nextPrepareFilter) {
        super(nextPrepareFilter);
    }
​
    @Override
    public void prepare(PreparationList preparationList) {
        if (preparationList.isWashFace()) {
            System.out.println("洗脸");
        }
​
    }
​
}

\