责任在哪?
责任链模式看名称可以理解为责任连成一条链。这也没有什么毛病,责任链模式的重点也在于“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果。
责任链模式的核心在“链”上,链是由多个处理者组成的。
“古代妇女的枷锁”——责任链的体现
中国古代对于妇女指定了“三从四德”的道德规范。“三从”是指“未嫁从父、既嫁从夫、夫死从子”,也就是说,一位女性在结婚前要听从于父亲,结婚后要听从于丈夫,如果丈夫死了还要听从于儿子。在父系社会中,妇女只占从属地位,想在想想中国古代的妇女还是挺悲惨的。
但是这与要讲的责任链模式有什么关系呢,确实没多大关系,只是通过这来举例说明下责任链的责任传递。假设目前是中国明朝,民间有一位女儿,生来美丽,她的一生有三种状态,未婚、已婚且丈夫健在、丈夫去世。有一天,她想去逛街,如果她处于未婚状态,则需要她向她的父亲发起一个请求是否可以去,而父亲收到这个请求后需要做出相应的回复。流程如下所示:
首先,这位女性会将去“逛街”这个请求发送给她的父亲,如何她父亲可以处理则会做出相应,否则父亲将该请求传递给她的丈夫处理,如果丈夫仍不能处理则会将请求传递给儿子进行处理。
先来看看女性这个接口以及它的实现,接口中有一个请求逛街的方法以及一个int
型属性,标识她目前处于未婚、已婚且丈夫健在还是丈夫去世的哪一种状态,这也决定了她的请求由父亲、丈夫还是儿子来处理。
//抽象女性接口
public interface AbstractWomen {
//状态等级,将决定由谁来处理她的请求
int getLevel();
//女性的请求是什么
String getRequest();
}
//女性接口实现
public class Women implements AbstractWomen{
private int level;
private String request;
public Women(int level, String request) {
this.level = level;
this.request = request;
}
@Override
public int getLevel() {
return this.level;
}
@Override
public String getRequest() {
return this.request;
}
}
上面定义了女性的接口,接下来如何实现处理者的接口呢,这里我们借用模板方法模式。
/**
* @author: zhangocean
* @Date: 2018/12/26 16:23
* Describe:处理类接口
*/
public abstract class Handler {
//定义三个等级状态
//1:未婚,由父亲相应
//2:已婚,丈夫健在,由丈夫相应
//3:丈夫去世,由儿子相应
public final static int FATHER_LEVEL = 1;
public final static int HUSBAND_LEVEL = 2;
public final static int SON_LEVEL = 3;
//处理者可处理等级
private int level;
//处理类相应内容
private String response;
//下一个处理者
private Handler nextHandler;
public Handler(int level) {
this.level = level;
}
public void handleMessage(AbstractWomen abstractWomen){
//责任链模式,责任传递
if(abstractWomen.getLevel() == level){
this.response(abstractWomen);
} else {
if(this.nextHandler != null){
this.nextHandler.handleMessage(abstractWomen);
} else {
System.out.println("没人处理");
}
}
}
public int getLevel() {
return level;
}
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
//处理者相应内容
abstract void response(AbstractWomen women);
}
使用责任链模式的精华就在于责任在链上的传递,在这个接口中我们使用到了模板方法模式,在抽象类中实现了handleMessage()
的方法体,即子类不需要重写该方法(该方法作为一个模板方法),在该方法中使用递归调用处理者处理事件,如果递归到链尾仍未匹配到则打印无人处理。
//父亲实现
public class Father extends Handler {
public Father() {
super(Handler.FATHER_LEVEL);
}
@Override
void response(AbstractWomen women) {
System.out.println("父亲处理请求:" + women.getRequest() + ",请求等级:" + women.getLevel());
}
}
//丈夫实现
public class Husband extends Handler {
public Husband() {
super(Handler.HUSBAND_LEVEL);
}
@Override
void response(AbstractWomen women) {
System.out.println("丈夫处理请求:" + women.getRequest() + ",请求等级:" + women.getLevel());
}
}
//儿子实现
public class Son extends Handler {
public Son() {
super(Handler.SON_LEVEL);
}
@Override
void response(AbstractWomen women) {
System.out.println("儿子处理请求:" + women.getRequest() + ",请求等级:" + women.getLevel());
}
}
处理者实现类比较简单,只需要在各个实现类中重写处理者相应内容即可。下面进程责任链测试代码:
public class Client {
public static void main(String[] args) {
Father father = new Father();
Husband husband = new Husband();
Son son = new Son();
//设置下一个传递的处理者
father.setNextHandler(husband);
husband.setNextHandler(son);
Random random = new Random();
List<AbstractWomen> list = new ArrayList<>();
for(int i=0;i<5;i++){
list.add(new Women(random.nextInt(4), "买衣服"));
}
for(AbstractWomen women : list){
//调用模板方法
father.handleMessage(women);
}
}
}
打印结果如下:
丈夫处理请求:买衣服,请求等级:2
没人处理
没人处理
没人处理
儿子处理请求:买衣服,请求等级:3
责任链模式剖析
代码剖析
在上述案例代码中,一共有三位处理者,父亲、丈夫和儿子,分别可以处理的时间等级为1、2、3。一共随机生成了5位女性,她们的等级状态通过随机数生成。每一位女性只需要将请求传递给链首的处理者去处理,如果链首的处理者无法处理该等级的请求,则会传递给下一个处理者,当然,这对于请求的女性来说是透明的,她们并不知道她们的请求会被哪个处理者处理。
每一位处理者需要设置他的下一个处理者,这样才能将处理者形成一条链。当检测到没有处理者能够处理请求时,需要及时的做出一定的判断。
优点
责任链模式很好的将请求以及相应分隔开,请求者可以不知道是谁处理的,处理者不用知道请求的全貌,两者解耦,提高系统灵活性。
缺点
责任链模式有非常显著的缺点。一是性能问题,责任链模式通过在链上遍历决定事件的处理者,然而如果链过长,将会导致性能降低。二是调试很不方便,特别是链比较长时,由于采用递归的方法,调试时逻辑可能比较复杂。