责任链模式
中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫
死从子”。也就是说,一位女性在结婚之前要听从于父亲,结婚之后要听从于丈夫,如果丈
夫死了还要听从于儿子。举例来说,如果一位女性要出去逛街,在她出嫁前必须征得父亲的
同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?那就得问问儿子是否允许自己出
去逛街。估计你接下来马上要问:“要是没有儿子怎么办?”那就请示小叔子、侄子等。在父
系社会中,妇女只占从属地位,现在想想中国古代的妇女还是挺悲惨的,连逛街都要多番请
示。作为父亲、丈夫或儿子,只有两种选择:要不承担起责任来,允许她或不允许她逛街;
要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则。下
面来看如何通过程序来实现“三从”,需求很简单:通过程序描述一下古代妇女的“三从”制
度。好,我们先来看类图,如图
类图非常简单,IHandler是三个有决策权对象的接口,IWomen是女性的代码,其实现也
非常简单
package ZeRenLianP;
public interface IWomen {
/**
* 一个是取得当前的个人状况getType,通过返回值决定是结婚了还
是没结婚、丈夫是否在世等
* @return
*/
public int getType();
/**
* 方法getRequest是要请示的内容,要出去逛街还是吃
饭
* @return
*/
public String getRequest();
}
package ZeRenLianP;
public class Women implements IWomen {
/**
* 通过一个int类型的参数来描述妇女的个人状况
* 1--未出嫁
* 2--出嫁
* 3--夫死
* @return
*/
private int type = 0;
private String request = "";
public Women(int type,String request){
this.type = type;
this.request = request;
}
@Override
public int getType() {
return this.type;
}
@Override
public String getRequest() {
return this.request;
}
}
package ZeRenLianP;
public interface IHandler {
public void HandleMessage(Women women);
}
package ZeRenLianP;
public class Father implements IHandler {
@Override
public void HandleMessage(Women women) {
System.out.println("女儿的请示是:"+women.getRequest());
System.out.println("父亲的答复是:同意");
}
}
package ZeRenLianP;
public class Husband implements IHandler {
@Override
public void HandleMessage(Women women) {
System.out.println("妻子的请示是:"+women.getRequest());
System.out.println("丈夫的答复是:同意");
}
}
package ZeRenLianP;
public class Son implements IHandler {
@Override
public void HandleMessage(Women women) {
System.out.println("母亲的请示是:"+women.getRequest());
System.out.println("儿子的答复是:同意");
}
}
package ZeRenLianP;
import java.util.ArrayList;
import java.util.Random;
public class Client {
public static void main(String[] args) {
Random random = new Random();
ArrayList<Women> womenArrayList =new ArrayList<>();
for (int i = 0; i<5 ; i++){
womenArrayList.add(new Women(random.nextInt(4),"guangjie"));
}
IHandler father = new Father();
IHandler husband = new Husband();
IHandler son = new Son();
for (Women women:womenArrayList){
if(women.getType() ==1){ //未结婚少女,请示父亲
System.out.println("\n--------女儿向父亲请示-------");
father.HandleMessage(women);
}else if(women.getType() ==2){ //已婚少妇,请示丈夫
System.out.println("\n--------妻子向丈夫请示-------");
husband.HandleMessage(women);
}else if(women.getType() == 3){ //母亲请示儿子
System.out.println("\n--------母亲向儿子请示-------");
son.HandleMessage(women);
}else{
//暂时什么也不做
}
}
}
}
代码有以下几个问题:
● 职责界定不清晰
对女儿提出的请示,应该在父亲类中做出决定,父亲有责任、有义务处理女儿的请示,
因此Father类应该是知道女儿的请求自己处理,而不是在Client类中进行组装出来,也就是说
原本应该是父亲这个类做的事情抛给了其他类进行处理,不应该是这样的。
● 代码臃肿
我们在Client类中写了if...else的判断条件,而且能随着能处理该类型的请示人员越
多,if...else的判断就越多,想想看,臃肿的条件判断还怎么有可读性?!
● 耦合过重
这是什么意思呢,我们要根据Women的type来决定使用IHandler的那个实现类来处理请
求。有一个问题是:如果IHandler的实现类继续扩展怎么办?修改Client类?与开闭原则违背
了!
● 异常情况欠考虑
妻子只能向丈夫请示吗?如果妻子(比如一个现代女性穿越到古代了,不懂什么“三从
四德”)向自己的父亲请示了,父亲应该做何处理?我们的程序上可没有体现出来,逻辑失
败了!
可以抽象成这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就
作出回应处理,如果女儿已经出嫁了,那就要把这个请求转发到女婿来处理,那女婿一旦去
天国报道了,那就由儿子来处理这个请求。
package ZeRenLianP;
public abstract class Handle {
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 Handle nextHandler;
//每个类都要说明一下自己能处理哪些请求
public Handle(int _level){
this.level = _level;
}
//一个女性(女儿、妻子或者是母亲)要求逛街,你要处理这个请求
public final void HandleMessage(Women women){
if (women.getType() == this.level){
this.response(women);
}else {
if (this.nextHandler != null){
this.nextHandler.HandleMessage(women);
}else {
System.out.println("没有人了,不同意");
}
}
}
/**
* 如果不属于你处理的请求,你应该让她找下一个环节的人,如女儿出嫁了,
* 还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
* @param
*/
public void setNext(Handle handle){
this.nextHandler = handle;
}
protected abstract void response(IWomen w);
}
package ZeRenLianP;
public class Father extends Handle {
public Father(){
super(Handle.FATHER_LEVEL_REQUEST);
}
@Override
protected void response(IWomen women) {
System.out.println("--------女儿向父亲请示-------");
System.out.println(women.getRequest());
System.out.println("父亲的答复是:同意\n");
}
}
package ZeRenLianP;
public class Husband extends Handle {
public Husband(){
super(Handle.HUSBAND_LEVEL_REQUEST);
}
@Override
protected void response(IWomen women) {
System.out.println("--------妻子向丈夫请示-------");
System.out.println(women.getRequest());
System.out.println("丈夫的答复是:同意\n");
}
}
package ZeRenLianP;
public class Son extends Handle {
public Son(){
super(Handle.SON_LEVEL_REQUEST);
}
@Override
protected void response(IWomen women) {
System.out.println("--------母亲向儿子请示-------");
System.out.println(women.getRequest());
System.out.println("儿子的答复是:同意\n");
}
}
package ZeRenLianP;
public class Women implements IWomen {
/**
* 通过一个int类型的参数来描述妇女的个人状况
* 1--未出嫁
* 2--出嫁
* 3--夫死
* @return
*/
private int type = 0;
private String request = "";
public Women(int type,String request){
this.type = type;
//this.request = request;
switch (type){
case 1:
this.request = "女儿的请求是:" + request;
break;
case 2:
this.request = "妻子的请求是:" + request;
break;
case 3:
this.request = "母亲的请求是:" + request;
}
}
@Override
public int getType() {
return this.type;
}
@Override
public String getRequest() {
return this.request;
}
}
package ZeRenLianP;
import java.util.ArrayList;
import java.util.Random;
public class Client1 {
public static void main(String[] args) {
//随机挑选几个女性
Random rand = new Random();
ArrayList<Women> arrayList = new ArrayList();
for(int i=0;i<5;i++){
arrayList.add(new Women(rand.nextInt(4),"我要出去逛街"));
}
//定义三个请示对象
Handle father = new Father();
Handle husband = new Husband();
Handle son = new Son();
//设置请示顺序
father.setNext(husband);
husband.setNext(son);
for (Women women:arrayList){
father.HandleMessage(women);
}
}
}
责任链模式定义如下:
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to
handle the request.Chain the receiving objects and pass the request along the chain until an object
handles it.(使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关
系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。)
抽象的处理者实现三个职责:一是定义一个请求的处理方法handleMessage,唯一对外开
放的方法;二是定义一个链的编排方法setNext,设置下一个处理者;三是定义了具体的请求
者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel和具体的处理任务echo。