`

责任链模式——Chain of Responsibility

 
阅读更多

一、总结《Java设计模式》Chapter12 Chain of Responsibility


  概述:The intent of the chain responsibility pattern is to avoid coupling the sender of a request to its receiver, by giving more than one object a chance to handle the request.

  举例:在本工程中,从底层的machine,到line, 到bay,到factory都被看作是MachineComponent(机器组件);其中machine属于类Machine,后三种属于MachineComposite类,如图所示。当找某个机器组件的负责人时,可能会向上找到它的上层组件的负责人,因为有可能一个工程师负责了一个bay的所有机器。


   上面举例会涉及以下优缺点:

1.advantage:
  The advantage of this design is that clients(发出请求者) of machine components don't have to determine how engineers(接收请求者) are assigned.Machine components isolate their clients from knowledge of how responsibilities are assigned.

 

2.disadvantages:
  在本例中还没有考虑:parent是否为null;责任链是否出现回路。另外两个弊端就是:不是所有的对象都有所有的方法(例如,顶层对象没有parent);负责机器的工程师change real time没法处理。另外,如果进一步扩充这个例子,引入Tool(工具)和ToolCart(工具车)会再引入一个问题——Tool没有getResponsible()方法,他是由所在ToolCart负责的。


 

  下面我们就把上面扩充后的例子做成“责任链模式”,类图如上,主要有以下思路:

1、仍然采用责任链的思路,这样可以将“请求发出者”和“请求最终 接受(处理)者”解耦合;

2、让所有的“请求直接 接受者”(MachineComponent,Tool,ToolCart都是)都实现一个接口,接口中有方法getResponsible(),让接收者自己来决定直接返回内部的responsible属性。显然,Tool类和ToolCart类实现这个方法是不同的,如下:

public ToolCart implements VisualizationItem{
    protected Engineer responsible;
    public Engineer getResponsible(){
      return responsible;
    }
    ...
}

 

public class Tool implements VisualizationItem{
    protected ToolCart toolCart; //工具所在的工具车
   public Engineer getResponsible(){
      return toolCart.getResponsible();
    }
    ...
}

通过1、2两点,提出请求的客户端代码就可以像下面一样简单了:

public class AmbitiousMenu2 {
    public Engineer getResponsible(VisualizationItem item) {
        return item.getResponsible();
    }
}

 

     可见,在本例中,向任何一个VisualizationItem子类发出请求均可(visualizationItem.getResponsible()),具体子类可能有两种处理方式——(1)直接由自己处理;(2)转交给其他visualizationItem处理,而这个visualizationItem是自己的parent. 在第(2)种方式中,明显看到了“责任链”/责任的转交。

 

二、“女子三从四德”

另外一个有趣的例子是《设计模式之禅》上的“女子三从四德”的例子:)有兴趣看看:

http://www.cnblogs.com/winkey4986/archive/2012/04/16/2445426.html

 

  中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫死从子”,也就是说一个女性,在没有结婚的时候要听从于父亲,结了婚后听从于丈夫,丈夫死了还要听儿子的,举个例子来说,一个女的要出去逛街,同样这样的一个请求,在她没有出嫁前她必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?一般都是男的比女的死的早,还要问问儿子是否允许自己出去逛街,估计你下边马上要问要是没有儿子怎么办?

  既然有这么多的问题,那我们要想办法来解决这些问题,我们可以抽象成这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就回应处理,如果女儿已经出嫁了,那就要把这个请求转发到女婿来处理,那女婿一旦去天国报道了,那就由儿子来处理这个请求,类似于这样请求:

  父亲、丈夫、儿子每个节点有两个选择:要么承担责任,做出回复;要么把请求转发到后序环节。结构分析的已经很清楚了,那我们看怎么来实现这个功能,先看类图:

 我们使用数字来代表女性的不同状态,1是未结婚,2是已经结婚的,而且丈夫建在,3是丈夫去世了的
 从类图上看,三个实现类Father、Husband、Son只要实现构造函数和父类的中抽象方法就可以了,具体怎么处理这些请求,都已经转移到了Hanlder抽象类中,我们来看Hanlder怎么实现:

/**
* 
* 
* 父系社会,那就是男性有至高权利,handler控制权
*/
public abstract class Handler {
//能处理的级别
private int level =0;
//责任传递,下一个人责任人是谁
private Handler nextHanlder;
//每个类都要说明一下自己能处理哪些请求
public Handler(int _level){
this.level = _level;
}
//一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
public final void HandleMessage(IWomen women){
if(women.getType() == this.level){
this.response(women);
}else{
if(this.nextHanlder != null){ //有后续环节,才把请求往后递送
this.nextHanlder.HandleMessage(women);
}else{ //已经没有后续处理人了,不用处理了
System.out.println("-----------没地方请示了,不做处理!---------\n");
}
}
}
/*
* 如果你属于你处理的返回,你应该让她找下一个环节的人,比如
* 女儿出嫁了,还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
*/
public void setNext(Handler _handler){
this.nextHanlder = _handler;
}
//有请示那当然要回应
public abstract void response(IWomen women);
}
 

  有没有看到,其实在这里也用到模版方法模式,在模版方法中判断请求的级别和当前能够处理的级别,如果相同则调用基本方法,做出反馈;如果不相等,则传递到下一个环节,由下一环节做出回应。基本方法response要各个实现类都要实现,我们来看三个实现类:

/**
*
* 父亲
*/
public class Father extends Handler {
//父亲只处理女儿的请求
public Father(){
super(1);
}
//父亲的答复
@Override
public void response(IWomen women) {
System.out.println("--------女儿向父亲请示-------");
System.out.println(women.getRequest());
System.out.println("父亲的答复是:同意\n");
}
}
 
/**
*
* 丈夫类
*/
public class Husband extends Handler {
//丈夫只处理妻子的请求
public Husband(){
super(2);
}
//丈夫请示的答复
@Override
public void response(IWomen women) {
System.out.println("--------妻子向丈夫请示-------");
System.out.println(women.getRequest());
System.out.println("丈夫的答复是:同意\n");
}
}

 

/**
*
* 儿子类
*/
public class Son extends Handler {
//儿子只处理母亲的请求
public Son(){
super(3);
}
//儿子的答复
public void response(IWomen women) {
System.out.println("--------母亲向儿子请示-------");
System.out.println(women.getRequest());
System.out.println("儿子的答复是:同意\n");
}
}

 

  这三个类都很简单,构造方法那是你必须实现的,父类已经定义了,子类不实现编译不通过,通过构造方法我们设置了各个类能处理的请求类型,Father只能处理请求类型为1(也就是女儿)的请求;Husband只能处理请求类型类2(也就是妻子)的请求;儿子只能处理请求类型为3(也就是目前)的请求。
      IWomen接口代码:

/**
* 
* 古代悲哀女性的总称
*/
public interface IWomen {
//获得个人状况
public int getType();
//获得个人请示,你要干什么?出去逛街?约会?还是看电影
public String getRequest();
}

 

Woman类:

/**
*
* 古代女性的总称
*/
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;
//为了显示好看点,我在这里做了点处理
switch(this.type){
case 1:
this.request = "女儿的请求是:" + _request;
break;
case 2:
this.request = "妻子的请求是:" + _request;
break;
case 3:
this.request = "母亲的请求是:" + _request;
}
}
//获得自己的状况
public int getType(){
return this.type;
}
//获得妇女的请求
public String getRequest(){
return this.request;
}
}
 

我们再来看Client类是怎么描述古代这一个礼节的:

/**
*
* 我们后人来看这样的社会道德
*/
@SuppressWarnings("all")
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);
}
}
}

 

运行结果如下:

   据说这个例子最初是《设计模式之禅》上的,特此注明,非我原创。

 

三、如何记忆“责任链模式”

      给所有的请求接受者(如“三从四德”中的Father、Husband、Son)一个统一的接口(Handler),接口中有统一的处理请求/消息的接口方法handleMessage(),至于每个请求接受者处理对handleMessage()的实现由两种策略——(1)直接由自己处理;(2)转交给其他Handler子类的handleMessage()处理,即“责任转交/责任链”。                              


 

  • 大小: 6.5 KB
  • 大小: 8 KB
  • 大小: 17.6 KB
  • 大小: 94.4 KB
  • 大小: 44.4 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics