故事从”三从四德”说起
中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫死从子”。现在我们模拟一个场景:如果一位女性要出去逛街,首先她必须征得父亲的同意,如果没有父亲就必须请求丈夫,那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街。顺序处理图如下:
父亲、丈夫、儿子每个节点有两个选择:要么承担责任,做出回应;要么把请求交给下一个处理者处理。结构分析得已经很清楚了,那我们看怎么来实现这个功能,类图如下:
Handler类的实现
public abstract class Handler {
public final static int FATHER_LEVEL_REQUEST = 1;
public final static int HUSBAND_LEVEL_REQUEST = 2;
public final static int SON_LEVEL_REQUEST = 3;
//能处理的级别
private int level =0;
//责任传递,下一个人责任人是谁
private Handler nextHandler;
//每个类都要说明一下自己能处理哪些请求
public Handler(int _level){
this.level = _level;
}
//一个女性(女儿、妻子或者是母亲)要求逛街,你要处理这个请求
public final void HandleMessage(IWomen women){
if(women.getType() == this.level){
this.response(women);
}else{
if(this.nextHandler != null){ //有后续环节,才把请求往后递送
this.nextHandler.HandleMessage(women);
}else{ //已经没有后续处理人了,不用处理了
System.out.println("---没地方请示了,按不同意处理---\n");
}
}
}
/*
* 如果不属于你处理的请求,你应该让她找下一个环节的人,如女儿出嫁了,
* 还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
*/
public void setNext(Handler _handler){
this.nextHandler = _handler;
}
//有请示那当然要回应
protected abstract void response(IWomen women);
}
父亲类
public class Father extends Handler {
//父亲只处理女儿的请求
public Father(){
super(Handler.FATHER_LEVEL_REQUEST);
}
//父亲的答复
protected void response(IWomen women) {
System.out.println("女儿向父亲请示:"+women.getRequest()); System.out.println("父亲的答复是:同意\n");
}
}
丈夫类
public class Husband extends Handler {
//丈夫只处理妻子的请求
public Husband(){
super(Handler.HUSBAND_LEVEL_REQUEST);
}
//丈夫请示的答复
protected void response(IWomen women) {
System.out.println("妻子向丈夫请示:"+women.getRequest()); System.out.println("丈夫的答复是:同意\n");
}
}
儿子类
public class Son extends Handler {
//儿子只处理母亲的请求
public Son(){
super(Handler.SON_LEVEL_REQUEST);
}
//儿子的答复
protected void response(IWomen women) {
System.out.println("母亲向儿子请示:"+women.getRequest()); System.out.println("儿子的答复是:同意\n");
}
}
这三个类都很简单,构造方法是必须实现的,父类框定子类必须有一个显式构造函数,子类不实现编译不通过。通过构造方法我们设置了各个类能处理的请求类型,Father只能处 理请求类型为1(也就是女儿)的请求;Husband只能处理请求类型类为2(也就是妻子)的 请求,儿子只能处理请求类型为3(也就是母亲)的请求,那如果请求类型为4的该如何处理呢?在Handler中我们已经判断了,如何没有相应的处理者(也就是没有下一环节),则视为不同意。
女性接口
public interface IWomen {
//获得个人状况
public int getType();
//获得个人请示,你要干什么?出去逛街?约会?还是看电影?
public String getRequest();
}
女性类
public class Women implements IWomen{
/*
* 通过一个int类型的参数来描述妇女的个人状况
* 1--未出嫁
* 2--出嫁
* 3--夫死
*/
private int type=0;
//妇女的请示
private String request = "";
//构造函数传递过来请求
public Women(int _type,String _request){
this.type = _type;
this.request = _request;
}
//获得自己的状况
public int getType(){
return this.type;
}
//获得妇女的请求
public String getRequest(){
return this.request;
}
}
我们再来看Client类是怎么描述古代这一个礼节的,
场景类如下
public class Client {
public static void main(String[] args) {
//随机挑选几个女性
Random rand = new Random();
ArrayList<IWomen> arrayList = new ArrayList();
for(int i=0;i<5;i++){
arrayList.add(new Women(rand.nextInt(4),"我要出去逛街"));
}
//定义三个请示对象
Handler father = new Father();
Handler husband = new Husband();
Handler son = new Son();
//设置请示顺序
father.setNext(husband);
husband.setNext(son);
for(IWomen women:arrayList){
father.HandleMessage(women);
}
}
}
在Client中设置请求的传递顺序,先向父亲请示,不是父亲应该解决的问题,则由父亲
传递到丈夫类解决,若不是丈夫类解决的问题则传递到儿子类解决,最终的结果必然有一个 返回,其运行结果如下所示。
--------妻子向丈夫请示------- 妻子的请求是:我要出去逛街 丈夫的答复是:同意
--------女儿向父亲请示------- 女儿的请求是:我要出去逛街 父亲的答复是:同意
--------母亲向儿子请示------- 母亲的请求是:我要出去逛街 儿子的答复是:同意
--------妻子向丈夫请示------- 妻子的请求是:我要出去逛街 丈夫的答复是:同意
--------母亲向儿子请示------- 母亲的请求是:我要出去逛街 儿子的答复是:同意
结果也正确,业务调用类Client也不用去做判断到底是需要谁去处理,而且Handler抽象 类的子类可以继续增加下去,只需要扩展传递链而已,调用类可以不用了解变化过程,甚至是谁在处理这个请求都不用知道。
责任链模式的优点
责任链模式非常显著的优点是将请求和处理分开。请求者可以不用知道是谁处理的,处 理者可以不用知道请求的全貌(例如在J2EE项目开发中,可以剥离出无状态Bean由责任链处 理),两者解耦,提高系统的灵活性。
责任链模式的缺点
责任链有两个非常显著的缺点:一是性能问题,每个请求都是从链头遍历到链尾,特别 是在链比较长的时候,性能是一个非常大的问题。二是调试不很方便,特别是链条比较长, 环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂。
责任链模式的注意事项
链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能。