2024-12-21
实战设计
0

目录

责任链模式
本质
使用场景
优点
缺点
实现方式
示例1
示例2
示例3
思考

在工作中经常在某些场景会用到一些设计模式,今天写一篇文档记录下责任链模式的使用。

责任链模式

责任链模式通过将多个处理器对象以链式结构串联起来,然后调用链路上处理器对象方法,直至链路上处理器都调用完成。

对于我们所了解的设计原则,责任链模式更符合单一职责原则迪米特原则,各个实现类只要关注的自己业务逻辑,按照我们定义好的顺序进行处理。

本质

解耦数据和行为分离,整体提高扩展性

使用场景

当对请求需要多种逻辑处理或者校验符合规则的对象时,可以使用责任链模式。

思考哪些场景能更好的适用`责任链模式`?

我看过一些文章,描述的是通过不同的处理器去处理对象,每个处理器开头就是校验请求是否匹配我当前的业务,那为什么不直接用适配器模式呢?

其实在某些场景中,结合设计模式,只是没有最好,只有更好,主要还是看自己的内功掌握的怎么样,如何去定义一个场景更贴合哪种设计模式才是真理,拿我个人理解而言,我更多的会在某些串行逻辑执行或者串行校验的业务,才会使用此模式,例如:业务A -> 业务B -> 业务C

优点

降低耦合度:发送者和接收者之间解耦。
简化对象:对象不需要知道链的结构。
灵活性:通过改变链的成员或顺序,动态地新增或删除责任。
易于扩展:增加新的请求处理类很方便。

缺点

性能影响:可能影响系统性能,且调试困难,可能导致循环调用。
难以观察:运行时特征不明显,可能妨碍除错。

实现方式

定义处理器接口:通常包含一个处理请求的方法,指定顺序或者一个指向下一个处理者的引用。 定义管理器类:可以通过管理器来管理责任链,管理器可以动态地增加或删除责任链成员以及指定顺序。

示例1

结合 Spring 的 Ordered 接口和 SmartInitializingSingleton 接口,实现指定顺序的处理器,交由 Spring 管理使用。

java
// 定义指定顺序的处理者接口 - 基于Spring实现 import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.core.Ordered; public interface BusinessChainHandler extends Ordered, SmartInitializingSingleton { void handle(InterfaceParamDTO param); }

定义不同的处理器实现

java
@Component public class OneChainHandler implements BusinessChainHandler { @Override public void handle(InterfaceParamDTO param) { System.out.println("链路中第一个执行逻辑!"); } @Override public int getOrder() { return 1; } @Override public void afterSingletonsInstantiated() { ChainHandlerManager.addChainHandler(this); } } @Component public class TwoChainHandler implements BusinessChainHandler { @Override public void handle(InterfaceParamDTO param) { System.out.println("链路中第二个执行逻辑!"); } @Override public int getOrder() { return 2; } @Override public void afterSingletonsInstantiated() { ChainHandlerManager.addChainHandler(this); } } @Component public class ThreeChainHandler implements BusinessChainHandler { @Override public void handle(InterfaceParamDTO param) { System.out.println("链路中第三个执行逻辑!"); } @Override public int getOrder() { return 3; } @Override public void afterSingletonsInstantiated() { ChainHandlerManager.addChainHandler(this); } }

责任链管理器也可以有不同实现,例如通过本地缓存实现,也可以定义为 Bean,交由 Spring 管理,通过Bean信息实例化完成时进行初始化操作。

对于管理器的这些实现方式有利有弊,像本地缓存可无需依赖Spring,调用简单,实现方便,但是需要考虑自定义的顺序,像基于Spring容器管理的方式更加快捷,缺点就是需要依赖注入,增加代码复杂度。

java
// 责任链管理器 - 本地缓存实现 public class ChainHandlerManager { private static final List<BusinessChainHandler> chainHandler = new ArrayList<>(); public static List<BusinessChainHandler> getChainHandler() { return chainHandler; } public static void addChainHandler(BusinessChainHandler handler) { chainHandler.add(handler); chainHandler.sort(Comparator.comparingInt(BusinessChainHandler::getOrder)); } public static void execute(InterfaceParamDTO param) { chainHandler.forEach(handler -> handler.handle(param)); } } // 责任链管理器 - 基于 Spring 容器管理实现 @Component public class SpringChainHandlerManager implements SmartInitializingSingleton { @Resource private OneChainHandler oneChainHandler; @Resource private TwoChainHandler twoChainHandler; @Resource private ThreeChainHandler threeChainHandler; private static final List<BusinessChainHandler> chainHandler = new ArrayList<>(); public static void execute(InterfaceParamDTO param) { chainHandler.forEach(handler -> handler.handle(param)); } @Override public void afterSingletonsInstantiated() { chainHandler.add(oneChainHandler); chainHandler.add(twoChainHandler); chainHandler.add(threeChainHandler); } }

以下对不同的实现方式进行测试。

java
@SpringBootTest(classes = XenergyMonitorApplication.class) class ChainHandlerManagerTest { @Resource private SpringChainHandlerManager springChainHandlerManager; @Resource private ApplicationContext applicationContext; @Autowired private List<BusinessChainHandler> businessChainHandlerList; @Test public void test() { ChainHandlerManager.execute(new InterfaceParamDTO()); System.out.println(); springChainHandlerManager.execute(new InterfaceParamDTO()); System.out.println(); Map<String, BusinessChainHandler> beansOfType = applicationContext.getBeansOfType(BusinessChainHandler.class); beansOfType.values().stream().sorted(Comparator.comparingInt(BusinessChainHandler::getOrder)).collect(Collectors.toList()).forEach(v -> v.handle(new InterfaceParamDTO())); System.out.println(); businessChainHandlerList.forEach(x -> x.handle(new InterfaceParamDTO())); } }

示例2

此示例与示例1一致,只不过是自定义排序,而不是通过 Spring 容器进行管理,需要结合管理器的方式进行调用。

java
// 定义指定顺序的处理者接口 - 自定义实现 import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.core.Ordered; public interface BusinessChainHandler { void sort(); void handle(InterfaceParamDTO param); }

示例3

此实现是通过主动设置下一个处理者的引用,来完成链式调用。也就是明确的指定下一个处理者,而不需要进行单独排序处理。

java
// 指向下一个处理者的引用的实现 import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.core.Ordered; public interface NextBusinessChainHandler { void next(InterfaceParamDTO param); void handle(InterfaceParamDTO param); }

以上的接口实现方式为,此实现只需要找到头节点即可

java
@Component public class OneNextBusinessChainHandler implements NextBusinessChainHandler { @Resource private TwoNextBusinessChainHandler twoNextBusinessChainHandler; @Override public void next(InterfaceParamDTO param) { twoNextBusinessChainHandler.handle(param); } @Override public void handle(InterfaceParamDTO param) { // 逻辑处理 System.out.println("链路中第一个执行逻辑!"); // 下个节点 this.next(param); } } @Component public class TwoNextBusinessChainHandler implements NextBusinessChainHandler { @Resource private ThreeNextBusinessChainHandler threeNextBusinessChainHandler; @Override public void next(InterfaceParamDTO param) { threeNextBusinessChainHandler.handle(param); } @Override public void handle(InterfaceParamDTO param) { // 逻辑处理 System.out.println("链路中第二个执行逻辑!"); // 下个节点 this.next(param); } } @Component public class ThreeNextBusinessChainHandler implements NextBusinessChainHandler { @Override public void next(InterfaceParamDTO param) { // 没有下一个调用了 } @Override public void handle(InterfaceParamDTO param) { // 逻辑处理 System.out.println("链路中第三个执行逻辑!"); // 下个节点 this.next(param); } }

思考

对于责任链模式的实现,网上的实现各式各样,其实只要我们掌握原理以后,就可有千变万化的玩法,就拿以上3种示例而言,可以相互组合,选择一种更适合自己的方式。

模式是在经验中积累的,是知识的结晶,而不是死板硬套的模子!不要因为一些写模式的书比较流行就膜拜了,自己要多加动脑思考代码上的实现真是就只能是这样吗? 是不是有更优秀的方式来替代呢?

本文作者:柳始恭

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!