责任链模式定义如下:(使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关
系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。)
责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请
求,并返回相应的结果,其通用类图如图所示:
责任链模式的优点:责任链模式非常显著的优点是将请求和处理分开。请求者可以不用知道是谁处理的,处
理者可以不用知道请求的全貌(例如在J2EE项目开发中,可以剥离出无状态Bean由责任链处
理),两者解耦,提高系统的灵活
责任链模式的缺点:责任链有两个非常显著的缺点:一是性能问题,每个请求都是从链头遍历到链尾,特别
是在链比较长的时候,性能是一个非常大的问题。二是调试不很方便,特别是链条比较长,
环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂。
责任链模式的注意事项:链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个
最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免
无意识地破坏系统性能
实践:
责任链在实际的项目中使用也是比较多的,我曾经做过这样一个项目,界面上有一个用
户注册功能,注册用户分两种,一种是VIP用户,也就是在该单位办理过业务的,一种是普
通用户,一个用户的注册要填写一堆信息,VIP用户只比普通用户多了一个输入项:VIP序列
号。注册后还需要激活,VIP和普通用户的激活流程也是不同的,VIP是自动发送邮件到用户
的邮箱中就算激活了,普通用户要发送短信才能激活,为什么呢?获得手机号码以后好发广
告短信啊!项目组就采用了责任链模式,甭管从前台传递过来的是VIP用户信息还是普通用
户信息,统一传递到一个处理入口通过责任链来完成任务的处理,类图如图16-5所示
实践一:
购买请求决策项目介绍
决策因素:价格
决策级别:组长,部长,副总,总裁
考虑扩展性
代码实现:
package 职责链模式;
public abstract class Approver {
Approver successor;
String name;
public Approver(String name){
this.name = name;
}
public abstract void processRequest(PurchaseRequest purchaseRequest);
public void setSuccessor(Approver successor) {
this.successor = successor;
}
}
package 职责链模式;
public class Client {
public Client(){}
public PurchaseRequest sendRequest(int type,int number,float price){
return new PurchaseRequest(type,number,price);
}
}
package 职责链模式;
/**部门*/
public class DepartmentApprover extends Approver{
public DepartmentApprover(String name){
super(name+"DepartmentLeader");
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (5000 <= purchaseRequest.getSum() && purchaseRequest.getSum()<10000) {
System.out.println("**This request "+purchaseRequest.getId()+" will be handled by "+this.name+" **");
} else {
successor.processRequest(purchaseRequest);
}
}
}
package 职责链模式;
/**组长*/
public class GroupApprover extends Approver{
public GroupApprover(String name){
super(name+"GroupLeader");
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getSum()<5000) {
System.out.println("**This request "+purchaseRequest.getId()+" will be handled by "+this.name+" **");
} else {
successor.processRequest(purchaseRequest);
}
}
}
package 职责链模式;
public class MainTest {
public static void main(String[] args) {
Client mClient = new Client();
Approver group = new GroupApprover("Tom");
Approver dept = new DepartmentApprover("Jerry");
Approver vice = new VicePresidentApprover("Kate");
Approver president = new PresidentApprover("Bush");
group.setSuccessor(dept);
dept.setSuccessor(vice);
vice.setSuccessor(president);
president.setSuccessor(group);
group.processRequest(mClient.sendRequest(1, 100, 40));
group.processRequest(mClient.sendRequest(2, 200, 40));
group.processRequest(mClient.sendRequest(3, 300, 40));
group.processRequest(mClient.sendRequest(4, 400, 140));
}
}
package 职责链模式;
/**老总*/
public class PresidentApprover extends Approver{
public PresidentApprover(String name){
super(name+"President");
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (50000<=purchaseRequest.getSum()) {
System.out.println("**This request "+purchaseRequest.getId()+" will be handled by "+this.name+" **");
} else {
successor.processRequest(purchaseRequest);
}
}
}
package 职责链模式;
//购买请求
public class PurchaseRequest {
private int type=0;
private int number = 0;
private float price=0;
private int id=0;
public PurchaseRequest(int type,int number,float price){
this.type = type;
this.number = number;
this.price = price;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getId() {
return (int)(Math.random()*1000);
}
public void setId(int id) {
this.id = id;
}
//计算总和
public float getSum(){
return number*price;
}
}
package 职责链模式;
/**副总*/
public class VicePresidentApprover extends Approver{
public VicePresidentApprover(String name){
super(name+"ViceLeader");
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (10000<=purchaseRequest.getSum()&&purchaseRequest.getSum()<50000) {
System.out.println("**This request "+purchaseRequest.getId()+" will be handled by "+this.name+" **");
} else {
successor.processRequest(purchaseRequest);
}
}
}
业务场景二:
申请聚餐费用
来考虑这样一个功能:申请聚餐费用的管理。
很多公司都有这样的福利,就是项目组或者是部门可以向公司申请一些聚餐费用,用于组织项目组成员或者是部门成员进行聚餐活动,以增进人员之间的情感,更有利于工作中的相互合作。
申请聚餐费用的大致流程一般是:由申请人先填写申请单,然后交给领导审查,如果申请批准下来了,领导会通知申请人审批通过,然后申请人去财务核领费用,如果没有核准,领导会通知申请人审批未通过,此事也就此作罢了。
不同级别的领导,对于审批的额度是不一样的,比如:项目经理只能审批500元以内的申请;部门经理能审批1000元以内的申请;而总经理可以审核任意额度的申请。
也就是说,当某人提出聚餐费用申请的请求后,该请求会由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求,一般申请人是把自己的申请提交给项目经理,或许最后是由总经理来处理他的请求,但是申请人并不知道应该由总经理来处理他的申请请求。
那么该怎样实现这样的功能呢?
1:定义职责的抽象类
首先来看看定义所有职责的抽象类,也就是所有职责的外观,在这个类里面持有下一个处理请求的对象,同时还要定义业务处理方法,示例代码如下:
package 职责链模式2;
public abstract class Handler {
/**
* 持有下一个处理请求的对象
*/
protected Handler successor = null;
/**
* 设置下一个处理请求的对象
* @param successor 下一个处理请求的对象
*/
public void setSuccessor(Handler successor){
this.successor = successor;
}
/**
* 处理聚餐费用的申请
* @param user 申请人
* @param fee 申请的钱数
* @return 成功或失败的具体通知
*/
public abstract String handleFeeRequest(String user,double fee);
}
(2)实现各自的职责
现在实现的处理聚餐费用流程是:申请人提出的申请交给项目经理处理,项目经理的处理权限是500元以内,超过500元,把申请转给部门经理处理,部门经理的处理权限是1000元以内,超过1000元,把申请转给总经理处理。
分析上述流程,对请求主要有三个处理环节,把它们分别实现成为职责对象,一个对象实现一个环节的处理功能,这样就会比较简单。
先看看项目经理的处理吧,示例代码如下:
package 职责链模式2;
public class ProjectManager extends Handler{
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//项目经理的权限比较小,只能在500以内
if (fee < 500) {
if ("小小".equals(user)) {
str = "项目经理同意"+user+"聚餐费用"+fee+"元的请求";
} else {
//其它人一律不同意
str = "项目经理不同意"+user+"聚餐费用"+fee+"元的请求";
}
return str;
} else {
//超过500,继续传递给级别更高的人处理
if(this.successor!=null){
return successor.handleFeeRequest(user, fee);
}
}
return str;
}
}
接下来看看部门经理的处理,示例代码如下:
package 职责链模式2;
public class DepManager extends Handler{
public String handleFeeRequest(String user, double fee) {
String str = "";
//部门经理的权限只能在1000以内
if(fee < 1000){
//为了测试,简单点,只同意小李申请的
if("小小".equals(user)){
str = "部门经理同意"+user+"聚餐费用"+fee+"元的请求";
}else{
//其它人一律不同意
str = "部门经理不同意"+user+"聚餐费用"+fee+"元的请求";
}
return str;
}else{
//超过1000,继续传递给级别更高的人处理
if(this.successor!=null){
return this.successor.handleFeeRequest(user, fee);
}
}
return str;
}
}
再看总经理的处理,示例代码如下:
public class GeneralManager extends Handler{
public String handleFeeRequest(String user, double fee) {
String str = "";
//总经理的权限很大,只要请求到了这里,他都可以处理
if(fee >= 1000){
//为了测试,简单点,只同意小李的
if("小小".equals(user)){
str = "总经理同意"+user+"聚餐费用"+fee+"元的请求";
}else{
//其它人一律不同意
str = "总经理不同意"+user+"聚餐费用"+fee+"元的请求";
}
return str;
}else{
//如果还有后继的处理对象,继续传递
if(this.successor!=null){
return successor.handleFeeRequest(user, fee);
}
}
return str;
}
}
使用职责链
那么客户端如何使用职责链呢,最重要的就是要先构建职责链,然后才能使用。示例代码如下:
package 职责链模式2;
public class Client {
public static void main(String[] args) {
//先要组装职责链
Handler h1 = new GeneralManager();
Handler h2 = new DepManager();
Handler h3 = new ProjectManager();
h3.setSuccessor(h2);
h2.setSuccessor(h1);
//开始测试
String ret1 = h3.handleFeeRequest("小小", 300);
System.out.println("the ret1="+ret1);
String ret2 = h3.handleFeeRequest("小张", 300);
System.out.println("the ret2="+ret2);
String ret3 = h3.handleFeeRequest("小小", 600);
System.out.println("the ret3="+ret3);
String ret4 = h3.handleFeeRequest("小张", 600);
System.out.println("the ret4="+ret4);
String ret5 = h3.handleFeeRequest("小小", 1200);
System.out.println("the ret5="+ret5);
String ret6 = h3.handleFeeRequest("小张", 1200);
System.out.println("the ret6="+ret6);
}
}