责任链模式
本文主讲设计模式之责任链模式,其精髓在于构建一条链条。
作者:zsl
一个例子
假设这样一个场景(不一定完全正确),有个员工需要向领导请示一定资金的使用,由于不同的金额级别(级别不同,金额不同),请示领导的级别假定也不一致。我们假设有三个领导岗位A、B、C,分别分别处理不同级别的金额,先用类图模拟该场景:
该类图很容易读懂,一个员工接口,包含两个方法;一个领导接口,包含一个处理请求的方法,我们用代码实现该类图:
1、员工接口及其实现类
/**
* 接口
* @author ZSL
*/
public interface IEmployee {
/**
* 获取请求的级别
* @return 级别
*/
Integer getType();
/**
* 获取请求内容
* @return 请求内容
*/
String getRequest();
}
/**
* @author zsl
* @date 2020/8/23
*/
public class Employee implements IEmployee{
/**
* 类型
*/
private Integer type;
/**
* 内容
*/
private String request;
public Employee(Integer type, String request) {
this.type = type;
this.request = request;
}
@Override
public Integer getType() {
return this.type;
}
@Override
public String getRequest() {
return this.request;
}
}
2、领导接口及其实现类
/**
* @author zsl
* @date 2020/8/23
*/
public interface ILeaderHandler {
/**
* 处理请求
*/
void handlerRequest(IEmployee employee);
}
/**
* @author zsl
* @date 2020/8/23
* 假定只处理级别1
*/
public class LeaderA implements ILeaderHandler{
@Override
public void handlerRequest(IEmployee employee) {
System.out.println("员工的请求是:"+employee.getRequest());
System.out.println("LeaderA的答复:同意!");
}
}
/**
* @author zsl
* @date 2020/8/23
* 假定只处理级别2
*/
public class LeaderB implements ILeaderHandler{
@Override
public void handlerRequest(IEmployee employee) {
System.out.println("员工的请求是:"+employee.getRequest());
System.out.println("LeaderB的答复:同意!");
}
}
/**
* @author zsl
* @date 2020/8/23
* 假定只处理级别3
*/
public class LeaderC implements ILeaderHandler{
@Override
public void handlerRequest(IEmployee employee) {
System.out.println("员工的请求是:"+employee.getRequest());
System.out.println("LeaderC的答复:同意!");
}
}
代码编写完毕,我们进行测试:
/**
* @author zsl
* @date 2020/8/23
*/
public class Client {
public static void main(String[] args) {
//准备数据
ArrayList<IEmployee> list = new ArrayList<>(3);
list.add(new Employee(1,"请求使用级别1的金额"));
list.add(new Employee(2,"请求使用级别2的金额"));
list.add(new Employee(3,"请求使用级别3的金额"));
//定义三个请示对象
ILeaderHandler leaderA = new LeaderA();
ILeaderHandler leaderB = new LeaderB();
ILeaderHandler leaderC = new LeaderC();
for (IEmployee emp:list) {
if (emp.getType()==1){
leaderA.handlerRequest(emp);
}else if (emp.getType()==2){
leaderB.handlerRequest(emp);
}else if (emp.getType()==3){
leaderC.handlerRequest(emp);
}else {
System.out.println("--------无法请示--------");
}
}
}
}
/**
结果:
员工的请求是:请求使用级别1的金额
LeaderA的答复:同意!
员工的请求是:请求使用级别2的金额
LeaderB的答复:同意!
员工的请求是:请求使用级别3的金额
LeaderC的答复:同意!
*/
测试结果显示,完全正确!不同级别的领导审批不同级别的金额,实现了这一需求。
结果正确,但是代码看起来很奇怪了,有几个问题:
1、首先看到client场景类,代码过于臃肿,if…else的判断条件,随着后期越来越多的领导审批,可以预想后期会有很多很多if…else,阅读成本高;
2、按照正常情况下,一般向某位领导请示,那么这位领导有义务、责任处理该请求,而这里确实client类进行组装,职责界限不清晰;
3、前面提到,后续可能会增加不同的领导审批,会有多个实现类,这样就得重新修改client类,耦合过高,违背开闭原则。
4、有可能出现本该去领导B请示,却去了领导A,这种情况没有处理方法。
针对以上这种问题,我们需要重新考虑。员工向领导请示,那么员工必须得到一个响应,不管是哪个领导批的,可能领导A,领导B,领导C…那么,我们可以串成一个"链条",A–>B–>C,每个领导要么承担责任作出回应,要么转发给后面的领导处理,如下图:
优化例子
从上面的分析我们知道,需要构建一个链条(链条是需要能够链接下一个处理对象),要符合相关的设计原则,我们重新设计类图:
我们调整了类图,领导实现类只需要实现父类中的抽象方法response就可以。我们看下具体实现。
抽象类LeaderHandler及其实现类:
/**
* @author zsl
* @date 2020/8/23
*/
public abstract class LeaderHandler {
/**级别1*/
public static final Integer LEVEL_1 = 1;
/**级别2*/
public static final Integer LEVEL_2 = 2;
/**级别3*/
public static final Integer LEVEL_3 = 3;
/**能处理的级别*/
private Integer level = 0;
/**责任传递,下一个责任人*/
private LeaderHandler nextHandler;
public LeaderHandler(Integer level) {
this.level = level;
}
public void setNextHandler(LeaderHandler nextHandler) {
this.nextHandler = nextHandler;
}
/**
* 子类实现回应,具体由子类决定
* @param employee
*/
protected abstract void response(IEmployee employee);
/**
* 处理请求
* @param employee
*/
public final void handlerRequest(IEmployee employee){
if (employee.getType().equals(this.level)){
this.response(employee);
}else {
if (this.nextHandler != null){
this.nextHandler.handlerRequest(employee);
}else {
System.out.println("----暂时无法请示,默认结果拒绝---");
}
}
}
}
/**
* @author zsl
* @date 2020/8/23
*/
public class LeaderA extends LeaderHandler {
public LeaderA() {
super(LeaderHandler.LEVEL_1);
}
@Override
protected void response(IEmployee employee) {
System.out.println("***向leadeA请示***");
System.out.println(employee.getRequest());
System.out.println("leaderA答复:同意!");
}
}
/**
* @author zsl
* @date 2020/8/23
*/
public class LeaderB extends LeaderHandler {
public LeaderB() {
super(LeaderHandler.LEVEL_2);
}
@Override
protected void response(IEmployee employee) {
System.out.println("***向leadeB请示***");
System.out.println(employee.getRequest());
System.out.println("leaderB答复:同意!");
}
}
/**
* @author zsl
* @date 2020/8/23
*/
public class LeaderC extends LeaderHandler {
public LeaderC() {
super(LeaderHandler.LEVEL_3);
}
@Override
protected void response(IEmployee employee) {
System.out.println("***向leadeC请示***");
System.out.println(employee.getRequest());
System.out.println("leaderC答复:同意!");
}
}
场景测试类及其结果:
/**
* @author zsl
* @date 2020/8/23
*/
public class LeaderC extends LeaderHandler {
public LeaderC() {
super(LeaderHandler.LEVEL_3);
}
@Override
protected void response(IEmployee employee) {
System.out.println("***向leadeC请示***");
System.out.println(employee.getRequest());
System.out.println("leaderC答复:同意!");
}
}
/**
***向leadeA请示***
请求使用级别1的金额
leaderA答复:同意!
***向leadeB请示***
请求使用级别2的金额
leaderB答复:同意!
***向leadeC请示***
请求使用级别3的金额
leaderC答复:同意!
*/
结果正确,场景类不用判断到底是哪个领导处理的,抽象类的子类可以往下增加下去,只需要扩展链条。这就是责任链模式。
定义
责任链模式的定义如下:
使得多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
从定义上看,责任链的重点就是链条,由一条链去处理相似的请求,并在链中决定谁来处理这个请求并返回相应的结果。优点非常显著,请求和处理分开,请求者不知道具体是谁处理的,处理者也不用知道请求的全貌,两者解耦,提高系统的灵活性。当然也有其缺点:从上面看到,链条必须从头遍历到尾,如果链条过长,性能会是一个大问题,这个需要在开发中注意。
另外,我们看到上面的例子中的final方法,这其实是一个模板方法模式的使用,感兴趣的读者可以了解一下这个设计模式。