责任链设计模式就是将原本复杂的混合在一起的处理逻辑进行拆分,按照业务、相关性等因素拆分到多个处理器中,每个处理器只负责一部分逻辑处理;在执行的时候,一个处理器接一个处理器的从前到后的执行,在结构上看就像一个链条,这也是责任链名字的由来。
责任链设计模式能够让代码结构更清晰,更易于应对日后的功能扩展。
场景举例
比如一张优惠券,在使用的时候,后台代码要根据下单信息来判断这张优惠券是否可用,涉及判断的条件非常多,判断因素假设包含:
1、坎级,比如这张优惠券需要满100减10,满200减20,那么当前订单金额是否满足100元或200元;
2、品牌或品类,比如这张优惠券只能用在购买康师傅品牌的商品;
3、支付类型,只能线上支付时使用这张优惠券;
4、可用对象,只有购买平台自售商品才能使用这张优惠券,购买三方店铺商品则不能使用这张优惠券(类似京东某些券只能购买平台自营商品)。
实际上的业务可能包含更多条件和因素,实际的判断逻辑也会更复杂。
如果我们将这些平铺直叙的堆砌到代码里,实际可能一个类中按照不同因素,添加多个方法,最终有一个入口方法组织这些方法来判断。
代码类似于:
//判断坎级方法
public boolean 坎级(Coupon c) {
...
}
//判断品牌或品类方法
public boolean 品牌或品类(Coupon c) {
...
}
//判断支付类型方法
public boolean 支付类型(Coupon c) {
...
}
//判断可用对象方法
public boolean 可用对象(Coupon c) {
...
}
//判断优惠券是否可用入口方法
public boolean 入口(Coupon c) {
坎级(Coupon c)
品牌或品类(Coupon c)
支付类型(Coupon c)
可用对象(Coupon c)
return 结果
}
上面这种写法相对还能够接受,但是如果有的开发者直接一个大方法包含了所有逻辑(搞一个5000行代码的方法),这对以后业务变更后的升级改造挖下了一个大大的坑。
那么我们用责任链如何改造呢?
1、首先定义接口,接口中定义handle方法
public interface IHandler {
boolean handle();
}
2、按照业务需要实现4个处理器,都实现了IHandler 接口,并实现了handle方法
import java.util.Random;
/**
* 坎级
*/
public class HandlerA implements IHandler {
@Override
public boolean handle() {
Random r = new Random();
//生成随机整数,能被2整除表示业务逻辑为true,否则为false
boolean b = r.nextInt(10)%2 == 0;
System.out.println("exec 坎级:" + b);
return b;
}
}
import java.util.Random;
/**
* 品牌或品类
*/
public class HandlerB implements IHandler {
@Override
public boolean handle() {
Random r = new Random();
boolean b = r.nextInt(10)%2 == 0;
System.out.println("exec 品牌或品类:" + b);
return b;
}
}
import java.util.Random;
/**
* 支付类型
*/
public class HandlerC implements IHandler {
@Override
public boolean handle() {
Random r = new Random();
boolean b = r.nextInt(10)%2 == 0;
System.out.println("exec 支付类型:" + b);
return b;
}
}
import java.util.Random;
/**
* 可用对象
*/
public class HandlerD implements IHandler {
@Override
public boolean handle() {
Random r = new Random();
boolean b = r.nextInt(10)%2 == 0;
System.out.println("exec 可用对象:" + b);
return b;
}
}
3、责任链执行
import java.util.ArrayList;
import java.util.List;
public class Client {
void handle(List<IHandler> hl) {
System.out.println("---全部执行---");
for(IHandler h:hl) {
//不管每个处理器的验证结果是否为true,都会把处理器执行一遍
h.handle();
}
}
void handle2(List<IHandler> hl) {
System.out.println("---某个执行器验证不通过则退出执行---");
for(IHandler h:hl) {
//如果验证不通过直接退出执行
if(!h.handle()) {
break;
}
}
}
public static void main(String[] args) {
List<IHandler> hl = new ArrayList<>();
IHandler ha = new HandlerA();
IHandler hb = new HandlerB();
IHandler hc = new HandlerC();
IHandler hd = new HandlerD();
hl.add(ha);
hl.add(hb);
hl.add(hc);
hl.add(hd);
Client c = new Client();
c.handle(hl);
c.handle2(hl);
}
}
我们的责任链的每个处理器用的list来保存,就是main函数的这段代码:
List<IHandler> hl = new ArrayList<>();
IHandler ha = new HandlerA();
IHandler hb = new HandlerB();
IHandler hc = new HandlerC();
IHandler hd = new HandlerD();
hl.add(ha);
hl.add(hb);
hl.add(hc);
hl.add(hd);
然后在handle方法中使用循环依次执行,最终形成了一个链条执行的效果。
这里的demo实现了两个handle方法,handle方法是不管每个处理器的验证结果是否为true,都会把处理器执行一遍,handle2方法是某个执行器验证不通过则退出执行,这个可以按照实际的业务场景需要来定。
其实责任链还有一种模式,就是每个handler类都持有下一个handle,也就是在上面demo的HandlerA 、HandlerB、HandlerC、HandlerD中定义一个IHandler接口类型的元素,这样每个处理器就可以保存这个处理器之后的处理器,这样再当前hander类执行完handle方法后,可以直接调用下一个handler的handle方法,这种更像是一种责任链。代码如下:
IHandler ha = new HandlerA();
IHandler hb = new HandlerB();
IHandler hc = new HandlerC();
IHandler hd = new HandlerD();
ha.setHandle(hb);
hb.setHandle(hc);
hc.setHandle(hd);
这样不使用list,也可以是多个处理器形成一个链条。
总结:
责任链就是将复杂的处理逻辑进行拆分,拆分成多个的处理器来逐个处理,各个处理器形成一个链条,每个处理器处理完后再传递给后续处理器继续处理。
责任链设计模式适用于复杂的逻辑判断处理的场景。