前言
设计模式重要性不言而喻。掌握了设计模式写法就好比学会了一套通用武林绝学,这篇属于责任链设计模式,闲话不多说
引入例子:
中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫死从子”,
也就是说一个女性,在没有结婚的时候要听从于父亲,结了婚后听从于丈夫,丈夫死了还要听儿子的,举
个例子来说,一个女的要出去逛街,同样这样的一个请求,在她没有出嫁前她必须征得父亲的同意,出嫁
之后必须获得丈夫的许可,那丈夫死了怎么办?一般都是男的比女的死的早,还要问问儿子是否允许自己
出去逛街,估计你下边马上要问要是没有儿子怎么办?请示小叔子、侄子等等,在父系社会中,妇女只占
从属地位,现在想想中国的妇女还是比较悲惨的,逛个街还要请示来请示去,而且作为父亲、丈夫、儿子
只有两种选择:要不承担起责任来告诉她允许或不允许逛街,要不就让她请示下一个人,这是整个社会体
系的约束,应用到我们项目中就是业务规则,那我们来看怎么把“三从”通过我们的程序来实现,需求很
简单:通过程序描述一下古代妇女的“三从”制度,好我们先看类图:
1.设计模式类图结构
看不懂类图?看下面的代码
1.Iwomen
public interface IWomen {
// 获得个人请示,你要干什么?出去逛街?约会?还是看电影
public String getRequestType();// 请求类型
// 获得个人状况
public int getType(); // 类型
}
2.Women
public class Women implements IWomen {
/*
* 通过一个int类型的参数来描述妇女的个人状况 1---未出嫁 2---出嫁 3---夫死
*/
public int type;
public String requestTypeString;
public Women(int type, String requestTypeString) {
super();
this.type = type;
this.requestTypeString = requestTypeString;
}
@Override
public String getRequestType() {
return requestTypeString;
}
@Override
public int getType() {
return type;
}
}
3.Ihandler
public interface Ihandler {
//一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
public void HandleMessage(IWomen women); //处理消息类型
}
4.son,father,husband
public class Son implements Ihandler {
@Override
public void HandleMessage(IWomen women) {
System.out.println("母亲的请示是: "+women.getRequestType());
System.out.println("儿子的答复是:同意");
}
}
public class Husband implements Ihandler {
@Override
public void HandleMessage(IWomen women) {
System.out.println("妻子的请示是: "+women.getRequestType());
System.out.println("丈夫的答复是:同意");
}
}
public class Father implements Ihandler {
@Override
public void HandleMessage(IWomen women) {
System.out.println("女儿的请示是: "+women.getRequestType());
System.out.println("父亲的答复是:同意");
}
}
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), "我要出去逛街"));
}
// 定义三个请示对象
Ihandler father = new Father();
Ihandler husband = new Husband();
Ihandler son = new Son();
for (IWomen iWomen : arrayList) {
switch (iWomen.getType()) {
case 1:
father.HandleMessage(iWomen);
break;
case 2:
husband.HandleMessage(iWomen);
break;
case 3:
son.HandleMessage(iWomen);
break;
default:
break;
}
}
}
}
运行结果:
妻子的请示是: 我要出去逛街
丈夫的答复是:同意
女儿的请示是: 我要出去逛街
父亲的答复是:同意
女儿的请示是: 我要出去逛街
父亲的答复是:同意
妻子的请示是: 我要出去逛街
丈夫的答复是:同意
这个能看懂吧,不知道啥意思?
责任链关注三个点:
1.要处理的内容 (询问是否可以出去逛街)
2.处理顺序 (询问顺序)
3.处理结果。(能不能去逛街)
“三从四德”的旧社会规范已经完整的表现出来了,你看谁向谁请示都定义出来了,但是你是不是发
现这个程序写的有点不舒服?有点别扭?有点想重构它的感觉?那就对了!这段代码有以下几个问题:
失去面向对象的意义。对女儿提出的请示,应该在父亲类中做出决定,父亲这个类应该是知道女儿的
请求应该自己处理,而不是在 Client 类中进行组装出来,也就是说原本应该是父亲这个类做的事情抛给了
其他类进行处理;
迪米特法则相违背。我们在 Client 类中写了 if…eles 的判断条件,你看这个条件体内都是一个接口
IHandler 的三个实现类,谁能处理那个请求,怎么处理,直接在实现类中定义好不就结了吗?你的类我知
道的越少越好,别让我猜测你类中的逻辑,想想看,把这段 if…else 移动到三个实现类中该怎么做?
耦合过重。这个什么意思呢,我们要根据 Women 的 type 来决定使用 IHandler 的那个实现类来处理请
求,我问你,如果 IHanlder 的实现类继续扩展怎么办?修改 Client 类?与开闭原则违背喽!
异常情况没有考虑。妻子只能向丈夫请示吗?如果妻子向自己的父亲请示了,父亲应该做何处理?我
们的程序上可没有体现出来。
既然有这么多的问题,那我们要想办法来解决这些问题,我们可以抽象成这样一个结构,女性的请求
先发送到父亲类,父亲类一看是自己要处理的,就回应处理,如果女儿已经出嫁了,那就要把这个请求转
发到女婿来处理,那女婿一旦去天国报道了,那就由儿子来处理这个请求,类似于这样请求:
父亲、丈夫、儿子每个节点有两个选择:要么承担责任,做出回复;要么把请求转发到后序环节。结
构分析的已经很清楚了,那我们看怎么来实现这个功能,先看类图:
看到这里就说明第一部分已经明白前面写法属于出力费力不讨好写法,下面重构后的写法才符合设计原则面向对象,单一职责。
1.handler 类
负责 链式调用传递逻辑处理,当然属于核心类
public abstract class Handler {
protected int level; // 能处理的级别
protected Handler nextHanlder;
public Handler(int level) {
this.level = level;
}
// 一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
public final void HandleMessage(IWomen women) {
// 处理消息类型
if (women.getType() == level) {
this.Respond(women);
} else {
if (nextHanlder != null) {
nextHanlder.HandleMessage(women);
} else {
System.out.println("-----------没地方请示了, 不做处理!---------\n");
}
}
}
public abstract void Respond(IWomen women);
/**
*
* 如果你属于你处理的返回,你应该让她找下一个环节的人,比如 女儿出嫁了,还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
*/
public void setNext(Handler _handler) {
this.nextHanlder = _handler;
}
}
2.son father,husband
分别告诉Handler 自己能干什么,其他不用操心。
public class Son extends Handler {
public Son() {
super(3);
}
@Override
public void Respond(IWomen women) {
System.out.println("母亲的请示是: " + women.getRequestType());
System.out.println("儿子的答复是:同意");
}
}
public class Husband extends Handler {
//丈夫只处理妻子的请求
public Husband() {
super(2);
}
@Override
public void Respond(IWomen women) {
System.out.println("--------妻子向丈夫请示-------");
System.out.println(women.getRequestType());
System.out.println("丈夫的答复是:同意\n");
}
}
public class Father extends Handler {
//父亲只处理女儿的请求
public Father() {
super(1);
}
@Override
public void Respond(IWomen women) {
System.out.println("女儿的请示是: " + women.getRequestType());
System.out.println("父亲的答复是:同意");
}
}
3.client
调用方式会有变化
/**
* 采用古代典故三从四德进行比较,很生动
*
* @author weichyang
*
* 责任链两个职责:
*
* 1.我能做的事情(向上去声明,我能做的事情) 2.有序责任链,链式调用序列需要提前指定,无序责任链,根据列表角标顺序取出来进行链式调用
* 3.责任链链式调用方,处理方,待处理的问题方。三个职责确认不可。
*
*/
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++) {
int ii = rand.nextInt(3) + 1;
arrayList.add(new Women(ii, "我要出去逛街"));
}
// 定义三个请示对象
Handler father = new Father();
Handler husband = new Husband();
Handler son = new Son();
// 组成有序调用链
father.setNext(husband);
husband.setNext(son);
for (IWomen iWomen : arrayList) {
father.HandleMessage(iWomen);
}
}
}
4.women 和 iwomen
没有变化。
运行结果:
女儿的请示是: 我要出去逛街
父亲的答复是:同意
--------妻子向丈夫请示-------
我要出去逛街
丈夫的答复是:同意
--------妻子向丈夫请示-------
我要出去逛街
丈夫的答复是:同意
母亲的请示是: 我要出去逛街
儿子的答复是:同意
母亲的请示是: 我要出去逛街
儿子的答复是:同意
结果也正确,业务调用类 Client 也不用去做判断到底是需要谁去处理,而且 Handler 抽象类的子类以
后可以继续增加下去,只是我们这个传递链增加而已,调用类可以不用了解变化过程,甚至是谁在处理这
个请求都不用知道。
以上讲解的就是责任链模式,你看 Father、Husband、Son 这三个类的处理女性的请求时是不是在传递
呀,每个环节只有两个选项:要么承担责任做出回应,要么向下传递请求。
下一篇 :分析okhttp的链式调用方式
引用:
24中设计模式介绍和六大设计原则.pdf