责任链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
责任链模式-当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式(Chain of Responsibility Pattern)
模式和结构定义
- Client:客户端,请求的发起者
- Handler:抽象处理者,声明一个请求方法,并在其中保持一个对下一个处理节点Handler对象的引用
- ConcreteHandler:具体处理角色,对请求进行处理;如果不能处理则将请求转发给下一个节点对象处理
应用实例
双十一活动,购买商品时,有很多优惠券活动,其中就包括满减券和折扣券。下面用责任链模式来实现一个使用优惠券购买商品的实例
定义优惠券业务逻辑接口
/**
* 优惠券业务逻辑接口
*
* @author shengyong.huang
* @date 2020-07-21
*/
public interface UseCouponBase {
/**
* 所有处理逻辑的方法
*
* @param couponList 责任链集合
* @param useCouponBase 自身对象
* @param discounts 折扣 3折/5折 0.3/0.5
*/
void doSomething(List couponList, UseCouponBase useCouponBase, BigDecimal discounts);
}
优惠券业务控制路由
/**
* 优惠券路由
*
* @author shengyong.huang
* @date 2020-07-21
*/
public class UseCouponChain implements UseCouponBase {
// 所有 case 列表
private List<UseCouponBase> mCaseList = new ArrayList<>();
// 索引,用于遍历所有 case 列表
private int index = 0;
// 添加 case
public UseCouponChain addBaseCase(UseCouponBase base) {
mCaseList.add(base);
return this;
}
@Override
public void doSomething(List couponList, UseCouponBase useCouponBase, BigDecimal discounts) {
//所有遍历完了,直接返回
if (index == mCaseList.size()) {
return;
}
//获取当前 case
UseCouponBase currentCase = mCaseList.get(index);
//修改索引值,以便下次回调获取下个节点,达到遍历效果
index++;
//调用 当前 case 处理方法
currentCase.doSomething(couponList, useCouponBase, discounts);
}
}
折扣券责任链处理
/**
* 折扣券处理
*
* @author shengyong.huang
* @date 2020-07-21
*/
public class DiscountChain implements UseCouponBase {
@Override
public void doSomething(List couponList, UseCouponBase useCouponBase, BigDecimal discounts) {
System.out.println("使用折扣券逻辑处理");
//使用折扣券逻辑处理(怎么使用的代码此处我就省略了,具体业务逻辑具体实现就行)
//交给下一个执行器处理
useCouponBase.doSomething(couponList, useCouponBase, discounts);
}
}
满减券责任链处理
/**
* 满减券处理
*
* @author shengyong.huang
* @date 2020-07-21
*/
public class MoneyOffChain implements UseCouponBase {
@Override
public void doSomething(List couponList, UseCouponBase useCouponBase, BigDecimal discounts) {
System.out.println("使用满减券逻辑处理");
//使用满减券逻辑处理(怎么使用的代码此处我就省略了,具体业务逻辑具体实现就行)
//交给下一个处理
useCouponBase.doSomething(couponList, useCouponBase, discounts);
}
}
测试方法
/**
* 测试方法
*
* @author shengyong.huang
* @date 2020-07-21
*/
public class TestMain {
public static void main(String[] args) {
//新建一个各类优惠券处理路由
UseCouponChain useCouponChain = new UseCouponChain();
//需要处理哪些优惠券按顺序添加进路由就行
useCouponChain.addBaseCase(new MoneyOffChain())
.addBaseCase(new DiscountChain());
/*这里couponList 是形参,
具体业务中可以是用户的可用优惠券列表,
可以传入执行器中进行业务逻辑处理*/
List couponList = new ArrayList<>();
//执行业务逻辑处理
useCouponChain.doSomething(couponList, useCouponChain, new BigDecimal(0));
}
}
运行结果
使用满减券逻辑处理
使用折扣券逻辑处理
优点和不足
优点:
- **请求者和接受者松散耦合,以及能动态组合职责。**弱化了发出请求的人和处理请求的人之间的关系。发出请求的人只需要向第一个具体的处理者发送请求,然后就可以不用管了,处理者会在责任链上自己寻找处理的方法。这样就解耦了处理者和请求者之间的关系。
- 可以动态的改变责任链。责任链还有的好处就是可以动态的改变责任,删除或者添加或者改变顺序。
- 让各个处理者专注于实现自己的职责。责任链模式同时还做到了处理者之间的解耦,处理者自己专注于自己的处理逻辑就好,不管其他处理者干什么。
缺点:
- 不能保证请求一定被接收。
- 可能不容易观察运行时的特征,有碍于除错
- **推卸责任也可能导致处理延迟。系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。**我们可以责任链模式需要在责任链上传播责任,直至找到合适的处理对象。这样提高了程序的灵活性,但同时也出现了处理的延迟,因为有一个寻找的过程。所以需要低延迟的情况下,就不应该使用责任链模式
使用场景
- 比如jsp servlet 的 Filter
- 有许多对象可以处理用户的请求,希望程序在运行期间自动确定处理用户的那个对象。
- 希望用户不必明确指定接受者的情况下,向多个接受者的一个提交请求。
- 程序希望动态制定可处理用户请求的对象集合。
补充
参考:
设计模式之责任链模式(Chain of Responsibility)
设计模式学习笔记之六:责任链模式
设计模式学习笔记(六:责任链模式)
12、责任链模式(设计模式笔记)
优惠券使用—责任链模式