案例需求
- 税务系统的收税逻辑:月收入<=5000时不纳税;5000<月收入<=8000时,超过5000部分缴纳5%的税费;8000<月收入<=15000时,在缴纳超出5000部分的税费后超过8000部分缴纳10%的税费;15000<月收入<=30000时,在缴纳超出5000部分和超出8000部分的税费后超过15000部分缴纳15%的税费。
- 不实用模式实现
/**
* 计算税费方法
* @return 应该缴纳的总税费
*/
public double calculateTaxation(TaxationCalculateRequest request) {
double monthlyIncome = request.getMonthlyIncome();
if (monthlyIncome <= 5000) {
return 0.0;
} else if (monthlyIncome <= 8000) {
//省略多个对象的协同作用
return (monthlyIncome - 5000) * 0.05;
} else if (monthlyIncome <= 13000) {
return (8000 - 5000) * 0.05 + (monthlyIncome - 8000) * 0.1;
} else if (monthlyIncome <= 30000) {
return (8000 - 5000) * 0.05 + (13000 - 8000) * 0.1 + (monthlyIncome - 13000) * 0.15;
}else if(monthlyIncome<=50000){
}
return -1;
}
问题
- (使用if--else if或者switch进行逻辑判断)
- 如果需要添加新的税费的缴纳标准或者调整原有的税费缴纳标准时就需要去修改税费服务类中原有的代码;
- 税费服务类必须知道所有的税费的计算标准,这样就使得税费服务类和税费计算逻辑具有一个强耦合关系;违反单一职能原则;
- 违反了开闭原则(OCP原则),可扩展性和可维护性就 极差。
概述
- 责任链模式,又叫职责链模式,将能够处理同一类请求的对象连成一条链,然后将请求的发送者和接收者进行了解耦;
- 责任链模式会将所提交的请求沿着接收者的链进行传递,链上的对象逐个判断是否有能力处理该请求,如果能处理则处理,如果不能处理就传递给接收者链上的下一个对象,以此类推。
责任链角色
Handler(抽象处理者):只能是一个抽象类,它定义了一个处理请求的方法, 同时包含另外 Handler的引用;ConcreteHandler(具体处理者):继承了抽象处理者,负责处理它能处理的请求,并可以访问它的下一个处理者,如果能处理当前请求则处理,如果不能处理就将该请求交给下一个处理者去处理,从而形成一个责任链;Request (请求对象):含有很多需要处理的属性,表示一个需要被处理的请求。- 使用责任链模式计算税费
/**
* 税费管理服务(抽象处理者)
* @author Peter
*/
public abstract class TaxationService {
protected int max;
/*
* 持有一个自己类型的引用也就是持有下一个
* 处理者
*/
protected TaxationService taxationService;
/**
* 也就是setNext方法
* @param taxationService
*/
public void setTaxationService(TaxationService taxationService) {
this.taxationService = taxationService;
}
/**
* 计算税费的方法
* @param request 税费请求对象
* @return 应缴纳的税费
*/
public abstract double calculateTaxation(TaxationCalculateRequest request);
}
/**
* 5000元及以下税费计算服务(具体处理者)
* @author Peter
*/
public class LessFiveThousandTaxationService extends TaxationService {
/**
* 计算税费的方法
* @param request 税费请求对象
* @return 应缴纳的税费
*/
public double calculateTaxation(TaxationCalculateRequest request) {
if (request.getMonthlyIncome() <= 5000) {
return 0.0;
}
return taxationService.calculateTaxation(request);
}
}
/**
* 8000元及以下税费计算服务(具体处理者)
* @author Peter
*/
public class LessEightThousandTaxationService extends TaxationService {
/**
* 计算税费的方法
* @param request 税费请求对象
* @return 应缴纳的税费
*/
public double calculateTaxation(TaxationCalculateRequest request) {
double monthlyIncome = request.getMonthlyIncome();
if (monthlyIncome <= 8000) {
return request.getBaseTaxation()+(monthlyIncome - 5000) * 0.05;
}
request.setBaseTaxation((8000 - 5000) * 0.05);
return taxationService.calculateTaxation(request);
}
}
// ...
// Client 使用方
//创建各个税费计算对象
TaxationService taxationService1=new LessFiveThousandTaxationService();
TaxationService taxationService2=new LessEightThousandTaxationService();
TaxationService taxationService3=new LessFifteenThousandTaxationService();
TaxationService taxationService4=new LessThirtyThousandTaxationService();
//构建计算的责任链
taxationService1.setTaxationService(taxationService2);
taxationService2.setTaxationService(taxationService3);
taxationService3.setTaxationService(taxationService4);
//计算月收入4500的税费
TaxationCalculateRequest request=new TaxationCalculateRequest();
request.setMonthlyIncome(4500);
double taxation = taxationService1.calculateTaxation(request);
模块一 使用责任链模式.jpg
总结
- 将请求和处理分开,实现解耦,提高了系统的灵活性遵守了单一职能原则;
- 简化了请求对象,使请求对象不需要知道链的结构,遵守了迪米特法则;
- 如果责任链比较长,那么系统性能会受到很大影响,因此需控制链中最大节点数量,一般通过在Handler 中设置一个最大节点数量,在setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链而影响系统性能的情况发生;
- 调试不方便,采用了类似递归的方式,调试时逻辑可能比较复杂必须跟着链去一个一个地寻找出错点;
典型运用场景举例
- OA系统中的请假、文件审批等审批流程,
- 学校教务系统中的奖学金审批、处分表扬审批,
- 电商系统中的多重打折和优惠叠加计算折后价格的场景。
源码中的责任链模式
- Servelet 的 Filter