在平时开发中如果遇到需要由多个不同的类对象来处理同一个请求时,你会怎么做呢?
if (condition) {
object1.invoke();
} else if (condition1) {
object2.invoke();
} else if (condition2) {
object3.invoke();
} ....
是像我这样么,满屏的if else。稍有经验的开发人员都明白这样的代码违反了开闭原则,修改任何一个条件都需要改动代码,到后期极难维护。
那该如何做呢?有很多设计模式都是为了解决这样的情况,不过今天我要讲的是责任链模式。
首先我们通过维基百科的定义来认识责任链模式:
责任 链模式包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。
上面说的比较抽象,我举个例子,平时工作中请假需要向领导发起审批,领导从低往高分为很多级,不可能随便请个假就直接到了老板那里,而是要根据请假天数来决定。但首先需要提交给你的直属领导审批,比如组长,如果请假范围在其权限范围内,则审批完成;如果超出权限范围,则由组长交由经理审批,以此类推,直到boss层级。这就是一个典型的责任链模式的应用。这里请假审批就是“命令对象”,而各个领导就是处理对象,每个领导都负责自己能处理的范围并且指向了下一个领导,像一条链一样串在一起,故此得名责任链模式。
将上面的过程实现为代码如下,首先是命令请求和处理级别类:
// 命令对象,即请求
public class Request {
// 权限级别,判断该请求属于哪个权限范围内
private Level level;
public Request(Level level) {
this.level = level;
}
public Level getLevel() {
return level;
}
}
// 权限级别
public class Level {
private int num;
public Level(int num) {
this.num = num;
}
public int getNum() {
return num;
}
}
接收处理者:
// 抽象的接收者
public abstract class Adminstration {
// 指向下一个接收者
protected Adminstration next;
// 接收者的权限范围,需要由子类各自设定
public abstract Level getLevel();
public void setNext(Adminstration next) {
this.next = next;
}
// 处理请求
public void process(Request request) {
// 比较发起者和接收者的权限级别,相同则可以处理,否则由下一个
// 接收者处理
int requestType = request.getLevel().getNum();
int mangeType = this.getLevel().getNum();
if (requestType == mangeType) {
System.out.println("由" + this.getClass().getName() + "审批");
return;
}
// 下一个接收者为空,表示已经到链的末端
if (next == null) {
System.out.println("没有人具有该审批权限!");
return;
}
next.process(request);
}
}
// 组长
public class TeamLeader extends Adminstration {
@Override
public Level getLevel() {
return new Level(1);
}
}
// 经理
public class Manager extends Adminstration {
@Override
public Level getLevel() {
return new Level(2);
}
}
最后发起审批测试结果如下:
public static void main(String[] args) {
Adminstration teamLeader = new TeamLeader();
Adminstration manager = new Manager();
Adminstration director = new Director();
Adminstration boss = new Boss();
teamLeader.setNext(manager);
manager.setNext(director);
director.setNext(boss);
Request request = new Request(new Level(4));
teamLeader.process(request);
}
// output:由cn.dark.chain.Director审批
实现很简单,将if else的各个条件拆分到了各个类里面,符合开闭原则以及单一职责原则,可以发现责任链模式非常适合单个请求需要由多个对象处理的情况。
那它岂不是和观察者模式很像?
没错,你思考的很认真,但它和观察者模式还是有很大区别的。
如果你不清楚观察者模式,可以先点过去看看我之前写的文章。如果你已经很熟悉两个模式了,那你应该很容易发现它们之间的区别。
观察者模式是一个发布者对应多个订阅者,发布者是将资源独立地推送给每一个订阅者,订阅者也可以主动从发布者拉取,无论哪种方法, 订阅者获取到的资源都是相互独立,各不影响的,并且,发布者不关注处理的结果。就像下面这样:
而责任链模式是将一个个处理者串链接起来,请求在处理者之间按链的方向游走,直到处理完毕,最终需要将处理结果响应给客户端(某些特殊情况下可能只是处理不需要响应)。
上面讲的都只讨论了单个对象处理完及完毕,那责任链模式是否适合多个对象需要协同配合处理请求的情况呢?有没有什么问题呢?
责任链模式很好的遵循了单一职责原则、开闭原则,客户端不必知道所有的处理者,使用时,也可以很容易的改变处理的顺序,但同时也会导致类的数目增加以及处理顺序设置不正确,需要注意。