设计模式之职责链模式

一.基本内容

1 . 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系;将这些对象连接成一条链,并沿着这条链传递该请求,直到有对象处理它停止;

2 . 职责链模式又称为责任链模式,为请求创建了一个接收者对象的链;把可以响应请求的对象组织成一条链,并在这条链上传递请求,从而保证多个对象都有机会处理请求并可以避免请求方和响应方的紧密耦合。

3 . 这种模式对请求的发送者和接收者进行解耦;

4 . 职责链模式通常每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依次类推传递;

5 . 这种类型的设计模式属于行为型模式

6 . 实例

  • 实现学校OA系统的采购审批项目;

  • 需求是:

采购员采购教学器材

如果金额 小于等于 5000, 由教学主任审批 (0<=x<=5000)

如果金额 小于等于10000, 由院长审批 (5000<=x<=10000)

如果金额 小于等于30000, 由副校长审批 (10000<=x<=30000)

如果金额 大于30000, 由校长审批 (x>30000)

  • 传统方案解决审批问题

传统方式是:接收到一个采购请求后,根据采购金额来调用对应的 Approver(审批人)完成审批。

传统方式的问题分析: 客户端这里会使用到分支判断(比如 switch) 来对不同的采购请求处理, 这样就存在如下问题 :

如果各个级别的人员审批金额发生变化,在客户端的也需要变化

客户端必须明确的知道 有多少个审批级别和访问

这样 对一个采购请求进行处理 和 Approver(审批人) 就存在强耦合关系,不利于代码的扩展和维护;

7 . 用职责链模式解决上述问题

//首先构造抽象类Approver
package designpattern.twentythree;
public abstract class Approver {
Approver approver;//下一个处理者
String name; //名字
public Approver(String name) {
   super();
   this.name = name;
}
public Approver getApprover() {
   return approver;
}
//下一个处理者
public void setApprover(Approver approver) {
   this.approver = approver;
}
//处理审批请求的方法,得到一个请求,处理是子类完成,因此为抽象
public abstract void processRequest(PurchaseRequest purchaseRequest);
}
//请求类
public class PurchaseRequest {
private int type;//请求类型
private float price = 0.0f;
private int id = 0;
public PurchaseRequest(int type, float price, int id) {
   super();
   this.type = type;
   this.price = price;
   this.id = id;
}
public int getType() {
   return type;
}
public void setType(int type) {
   this.type = type;
}
public float getPrice() {
   return price;
}
public void setPrice(float price) {
   this.price = price;
}
public int getId() {
   return id;
}
public void setId(int id) {
   this.id = id;
}
}
//各个级别的处理人的实现类
//系主任
public class DepartmentApprover extends Approver{
public DepartmentApprover(String name) {
   super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
   if(purchaseRequest.getPrice() <= 5000) {
       System.out.println("请求编号id="+purchaseRequest.getId()+" 被"+this.name+" 处理");
   }else {
       approver.processRequest(purchaseRequest);
   }

}

}
//院长
public class CollegeApprover extends Approver{
public CollegeApprover(String name) {
   super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
   if( 5000 < purchaseRequest.getPrice() &&purchaseRequest.getPrice() <= 10000) {
       System.out.println("请求编号id="+purchaseRequest.getId()+" 被"+this.name+" 处理");
   }else {
      approver.processRequest(purchaseRequest);
   }
}
}
//副校长
public class ViceMasterApprover extends Approver {
public ViceMasterApprover(String name) {
   super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
   if( 10000 < purchaseRequest.getPrice() &&purchaseRequest.getPrice() <= 30000) {
       System.out.println("请求编号id="+purchaseRequest.getId()+" 被"+this.name+" 处理");
    }else {
       approver.processRequest(purchaseRequest);
   }
}
}
//校长
public class SchoolMasterApprover extends Approver{
public SchoolMasterApprover(String name) {
   super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
   if( 30000 < purchaseRequest.getPrice()) {
      System.out.println("请求编号id="+purchaseRequest.getId()+" 被"+this.name+" 处理");
   }else {
      approver.processRequest(purchaseRequest);
   }


}
}
//测试类
public class Client {
public static void main(String[] args) {
   //创建一个请求
   PurchaseRequest p = new PurchaseRequest(1,3000,1);
   //创建相关的审批人
   DepartmentApprover d = new DepartmentApprover("张主任");
   CollegeApprover c = new CollegeApprover("李院长");
   ViceMasterApprover v = new ViceMasterApprover("王副校长");
   SchoolMasterApprover s = new SchoolMasterApprover("朱校长");
   //需要将各个审批级别的下一个设置好(处理人构成环形)
   d.setApprover(c);
   c.setApprover(v);
   v.setApprover(s);
   s.setApprover(d);
   d.processRequest(p);
}
}

二.应用

1 . 优点

(1) 职责链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。

(2) 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。

(3) 在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。

(4) 在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的。

2 . 缺点

性能问题,每个请求都是从链头遍历到尾,特别是链比较长的时候,性能是很大问题

3 . 在SpringMVC中使用了职责链模式

4.注意事项

  • 将请求和处理分开,实现解耦,提高系统的灵活性

  • 简化了对象,使对象不需要知道链的结构

  • 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过Handler 中设置一个最大节点数量,在 setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能

  • 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂

  • 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程Java Web中 Tomcat对Encoding 的处理、拦截器

你可能感兴趣的:(设计模式,java,开发语言)