代码改变世界

设计模式之职责链模式

2013-05-24 15:36  youxin  阅读(735)  评论(0编辑  收藏  举报

模式动机:

 在很多情况下,可以处理某个请求的对象不止一个,如大学里的奖学金审批,学生在向辅导员提交审批表之后,首先是辅导员签字审批,然后交给系主任签字审批,接着是院长审批,最后可能是校长审批,在这个过程中,奖学金申请表可以看成是一个请求对象,而不同级别的审批者都可以处理该请求对象,除了辅导员之外,学生不需要一一和其他审批者交互,只需等待结果即可。在审批过程中如果某一个审批者任务不符合条件,则请求中止;否则将请求递交给下一个审批者,最后由校长来确定谁能够授予奖学金。该过程如下:

在图中,从辅导员直到校长都可以处理申请表,而且他们构成了一条链,申请表沿着这条链传递,这条链就叫职责链。

 职责链可以是一条直线,一个环或则一个树形结构,最常见的是直线型,即沿着一条单向的链来传递请求。链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并使请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,将请求的发送者和请求的处理者解耦。这就是职责链模式的模式动机。(客户类只需关心链的源头,而无需关心请求的处理细节及请求的传递过程

模式定义:

 职责链模式Chain of responsibility pattern:

 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。由于英文翻译的不同,职责链模式又称为责任链模式,它是一种对象行为型模式
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.
 
 uml:
Handler:抽象处理者,定义了一个处理请求的接口,它一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家是一个处理者,因此在抽象处理者中定义了一个自类型(抽象处理者类型)的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链
ConcreteHandler:在处理请求之前需要进行判断,看是否有相应的处理权,如果可以处理请求就处理它,否则将请求转发给后继者
Client:
 用于向链中的对象提出最初的请求,客户类只需要关心链的源头,而无需关心请求的处理细节以及请求的传递过程
 
职责链模式的核心在于抽象处理者类的设计,在抽象处理者中定义了一个自类型的对象,用于维持一个对处理者下家的引用,一遍将请求传递给下家,抽象处理者的典型代码如下:
public abstract class Handler
{
  protected Handler successor;
 
public void setSuccessor(Handler successor)
{
   this.successor=successor;
}
 
public abstract void handleRequest(String request);
}
 
具体处理者是抽象处理者的子类,代码如下:
public class ConcreteHandler extends Handler
{
   public void handleRequest(String request)
  {
   if(请求request满足条件)
  {
      ......  //处理请求;
  }
 else
  {
    this.successor.handleRequest(request); //转发请求
  }
 }
}
 需要注意的是,职责链模式并不创建职责链,职责链的创建工作必须由系统的其他部分来完成,一般是在该职责链的客户端中创建职责链
实例:
ü实例:审批假条
•某OA系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该假条;如果员工请假天数大于等于3天,小于10天,经理可以审批;如果员工请假天数大于等于10天,小于30天,总经理可以审批;如果超过30天,总经理也不能审批,提示相应的拒绝信息。
 
 
代码:
请求类:
package 审批假条;

public class LeaveRequest {
    private String leaveName;
    private int leaveDays;
    public LeaveRequest(String leaveName,int leaveDays)
    {
        this.leaveName=leaveName;
        this.leaveDays=leaveDays;
    }
    public String getLeaveName() {
        return leaveName;
    }
    public void setLeaveName(String leaveName) {
        this.leaveName = leaveName;
    }
    public int getLeaveDays() {
        return leaveDays;
    }
    public void setLeaveDays(int leaveDays) {
        this.leaveDays = leaveDays;
    }
}

抽象处理者Leader类:

public abstract class Leader {
    protected String name;
    protected Leader successor;
    public Leader(String name)
    {
        this.name=name;
    }
    
    public void setSuccessor(Leader successor)
    {
        this.successor=successor;
    }
    
    public abstract void handleRequest(LeaveRequest request);
    

}

具体处理者Director主任类:

public class Director extends Leader{
    
    public Director(String name)
    {
        super(name);
    }
    public void handleRequest(LeaveRequest request)
    {
        if(request.getLeaveDays()<3)
        {
            System.out.println("主任"+name+"审批员工"+request.getLeaveName()+"的请假条,请假天数为"+request.getLeaveDays()+"天");
            
        }
        else
        {
            if(this.successor!=null)
            {
                this.successor.handleRequest(request);
            }
        }
    } 

}

Manager类:

public class Manager extends Leader {

    public Manager(String name)
    {
        super(name);
    }
    public void handleRequest(LeaveRequest request) 
    {
         if(request.getLeaveDays()<10)
         {
             System.out.println("经理"+name+"审批员工"+request.getLeaveName()+"的请假条,请假天数为"+request.getLeaveDays()+"天");
         }
         else
         {
             if(this.successor!=null)
             {
                 this.successor.handleRequest(request);
             }
         }

    }
  
}
View Code

GeneralManager总经理类:]

public class GeneralManager extends Leader {

    public GeneralManager(String name)
    {
        super(name);
    }
    public void handleRequest(LeaveRequest request) 
    {
         if(request.getLeaveDays()<30)
         {
             System.out.println("宗经理"+name+"审批员工"+request.getLeaveName()+"的请假条,请假天数为"+request.getLeaveDays()+"天");
         }
         else
         {
             System.out.println("莫非"+request.getLeaveName()+"想辞职,居然请假"+request.getLeaveDays()+"天");
         }

    }

}
View Code

Client类:

public class Client {
 
    public static void main(String[] args) {
        
        Leader objDirector,objManager,objGeneralManager;
        
        objDirector=new Director("王明");
        objManager=new Manager("赵强");
        objGeneralManager=new GeneralManager("李波");
        
        objDirector.setSuccessor(objManager);
        objManager.setSuccessor(objGeneralManager);
        
        
        LeaveRequest lr1=new LeaveRequest("张三",2);
        objDirector.handleRequest(lr1);
        
        LeaveRequest lr2=new LeaveRequest("张四",5);
        objDirector.handleRequest(lr2);
        
        LeaveRequest lr3=new LeaveRequest("张五",15);
        objDirector.handleRequest(lr3);
        
        LeaveRequest lr4=new LeaveRequest("张六",45);
        objDirector.handleRequest(lr4);
        
    }

}

运行结果:

主任王明审批员工张三的请假条,请假天数为2天
经理赵强审批员工张四的请假条,请假天数为5天
宗经理李波审批员工张五的请假条,请假天数为15天
莫非张六想辞职,居然请假45天

要想增加新的处理者,建立一个处理者类然后在客户端修改successor即可。

职责链模式优点:

•降低耦合度
• 可简化对象的相互连接
• 增强给对象指派职责的灵活性:在给对象分配职责时,职责链可以给我们带来更多的灵活性。可以通过在运行时对该链进行动态的增加或改变处理一个请求 的职责。
• 增加新的请求处理类很方便
ü职责链模式的缺点
•不能保证请求一定被接收:既然一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;
•系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。
 
模式应用;
java中的异常处理机制类似一种职责链模式,可以我们在一个try语句后面接多个catch语句,而而每个catch语句可以捕获不同的异常,当第一个异常不匹配时,自动跳到第二个catch语句,直到所有的catch都匹配为止:
try
{
    ……
}
catch(ArrayIndexOutOfBoundsException e1)
{
    ……
}
catch(ArithmeticException e2)
{
    ……
}
catch(IOException e3)
{
    ……
}
finally
{
    ……
}
 2.冒泡模型。
 
职责链模式扩展:
ü纯与不纯的职责链模式
•一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:一个是承担责任,另一个是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又将责任向下传的情况。
•在一个纯的职责链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的职责链模式里面,一个请求可以最终不被任何接收端对象所接收。
纯的职责链模式是不容易找到的,一般看到的例子都是不纯的职责链模式,如java awt1.0的事件处理模式,由于每一级的组件在接收到事件时,都可以处理该事件,而不论此事件是否在这一级得到处理,事件都可以停止向上传播或继续向上传播,可以随时中断对事件的处理,这是典型的不纯的责任链模式。