在工作中经常在某些场景会用到一些设计模式,今天写一篇文档记录下责任链模式
的使用。
责任链模式通过将多个处理器对象以链式结构串联起来,然后调用链路上处理器对象方法,直至链路上处理器都调用完成。
对于我们所了解的设计原则,责任链模式更符合单一职责原则
和迪米特原则
,各个实现类只要关注的自己业务逻辑,按照我们定义好的顺序进行处理。
解耦数据和行为分离,整体提高扩展性
当对请求需要多种逻辑处理或者校验符合规则的对象时,可以使用责任链模式。
思考哪些场景能更好的适用`责任链模式`?
我看过一些文章,描述的是通过不同的处理器去处理对象,每个处理器开头就是校验请求是否匹配我当前的业务,那为什么不直接用适配器模式
呢?
其实在某些场景中,结合设计模式,只是没有最好,只有更好
,主要还是看自己的内功掌握的怎么样,如何去定义一个场景更贴合哪种设计模式才是真理,拿我个人理解而言,我更多的会在某些串行逻辑执行或者串行校验的业务,才会使用此模式,例如:业务A -> 业务B -> 业务C
降低耦合度:发送者和接收者之间解耦。
简化对象:对象不需要知道链的结构。
灵活性:通过改变链的成员或顺序,动态地新增或删除责任。
易于扩展:增加新的请求处理类很方便。
性能影响:可能影响系统性能,且调试困难,可能导致循环调用。
难以观察:运行时特征不明显,可能妨碍除错。
定义处理器接口:通常包含一个处理请求的方法,指定顺序或者一个指向下一个处理者的引用。 定义管理器类:可以通过管理器来管理责任链,管理器可以动态地增加或删除责任链成员以及指定顺序。
结合 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()));
}
}
此示例与示例1一致,只不过是自定义排序,而不是通过 Spring 容器进行管理,需要结合管理器的方式进行调用。
java// 定义指定顺序的处理者接口 - 自定义实现
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.core.Ordered;
public interface BusinessChainHandler {
void sort();
void handle(InterfaceParamDTO param);
}
此实现是通过主动设置下一个处理者的引用,来完成链式调用。也就是明确的指定下一个处理者,而不需要进行单独排序处理。
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 许可协议。转载请注明出处!