编写背景
存在这样一个需求,编写一个接口,底层需要顺序调用多个具备相同功能的接口,且如果当前接口不能处理该请求,则交给第二个接口去处理,以此类推,直到处理完成返回,且要求可以动态改变调用顺序和是否调用所选接口,因此研究了下责任链模式,并结合需求抽象化代码。
什么是责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它将请求的发送者和接收者解耦,使得多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。该模式在请求的处理过程中,每个对象都有一个处理的责任范围,而责任链中的每个对象都有机会处理请求,直到请求被处理完毕。
应用场景
- 处理请求需要遵循一定的处理顺序,且处理顺序可能会发生变化。
- 处理请求的对象不确定,需要动态地指定处理请求的对象。
- 处理请求的对象可以在运行时被修改。
- 可以通过将多个处理器组合成一个链,来完成请求的处理。
代码介绍
AbstractCallChain
public abstract class AbstractCallChain {
private AbstractCallChain nextChain;
/**
* 构造函数,基于下一个节点构建当前节点,为空时表示当前节点为最后一个节点(无下面一个节点)
* @param nextChain 下一个节点
*/
public AbstractCallChain(AbstractCallChain nextChain){
if (null != nextChain){
if (this.equals(nextChain)){
throw new RuntimeException("无法把自己作为下一个调用节点添加");
}
this.nextChain = nextChain;
}
}
public final Object doChain(Object param){
Object result = process(param);
if (null == result && null != nextChain){
result = nextChain.doChain(param);
}
return result;
}
protected abstract Object process(Object param);
}
- 该类是一个抽象类,表示一个基本的调用链节点。
- 它有一个私有的成员变量
nextChain
,表示下一个调用链节点。 - 在构造函数中,可以传入一个
AbstractCallChain
类型的参数nextChain
,用于构造下一个节点。 - 该类中定义了一个核心方法
doChain
,它接收一个参数param
,表示请求的参数,返回一个Object
类型的结果。 - 在执行
doChain
方法时,会首先调用当前节点的process
方法进行处理,并返回处理结果。如果处理结果为null
,则将请求传递给下一个节点进行进一步处理。如果没有下一个节点,则直接返回null
。由于该类是抽象类,因此需要被继承并实现process
方法才能被使用。
可以通过自定义标准的输入与输出类,并判断是否执行下一个节点
PriorityChainWrapper
public class PriorityChainWrapper{
/**
* key是优先级,value是类名
*/
private Map<Integer,String> priorityChainMap;
private AbstractCallChain chain;
public PriorityChainWrapper (Map<Integer,String> priorityChainMap){
try {
//排序
List<Integer> keyList = priorityChainMap.keySet().stream().sorted().collect(Collectors.toList());
this.priorityChainMap = priorityChainMap;
this.chain = buildChain(new Object[]{null},keyList);
}catch (Exception e){
throw new RuntimeException(e);
}
}
private AbstractCallChain buildChain(Object[] params,List<Integer> keyList) throws Exception {
AbstractCallChain result = null;
if (keyList.size() > 1){
//取最大的一条出来
keyList = keyList.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
Integer priority = keyList.get(0);
String className = priorityChainMap.get(priority);
keyList.remove(priority);
AbstractCallChain next = buildChain(params,keyList);
result = (AbstractCallChain) ConstructorUtils.invokeConstructor(Class.forName(className),new Object[]{next});
}else{
Integer priority = keyList.get(0);
String className = priorityChainMap.get(priority);
result = (AbstractCallChain) ConstructorUtils.invokeConstructor(Class.forName(className),params);
}
return result;
}
public Object doChain(Object param){
if (null == chain){
return null;
}
return chain.doChain(param);
}
}
- 该类是一个优先级责任链的包装类,它封装了一个
AbstractCallChain
类型的调用链,根据传入的优先级顺序构建调用链节点。 - 在构造函数中,接收一个
Map<Integer,String>
类型的参数priorityChainMap
,其中key
表示节点的优先级,value
表示节点的全限定类名。 - 构造函数会根据传入的
priorityChainMap
参数构建出一个完整的调用链,并赋值给成员变量chain
。 - 在该类中,有一个公共方法
doChain
,它用于执行调用链中的节点。 - 在执行
doChain
方法时,会首先判断调用链是否为空,如果为空则直接返回null
。否则,调用调用链的doChain
方法进行处理,并返回处理结果。
示例
构建三个测试调用链
调用链1
/**
* 调用链例子1
*/
public class CallChainDemoOne extends AbstractCallChain {
/**
* 构造函数,基于下一个节点构建当前节点,为空时表示当前节点为最后一个节点(无下面一个节点)
*
* @param nextChain 下一个节点
*/
public CallChainDemoOne(AbstractCallChain nextChain) {
super(nextChain);
}
@Override
public Object process(Object param) {
System.out.println("执行CallChainDemoOne");
return null;
}
}
调用链2
public class CallChainDemoTwo extends AbstractCallChain {
/**
* 构造函数,基于下一个节点构建当前节点,为空时表示当前节点为最后一个节点(无下面一个节点)
*
* @param nextChain 下一个节点
*/
public CallChainDemoTwo(AbstractCallChain nextChain) {
super(nextChain);
}
@Override
public Object process(Object param) {
System.out.println("执行CallChainDemoTwo");
return null;
}
}
调用链3
/**
* 调用链例子3
*/
public class CallChainDemoThree extends AbstractCallChain {
/**
* 构造函数,基于下一个节点构建当前节点,为空时表示当前节点为最后一个节点(无下面一个节点)
*
* @param nextChain 下一个节点
*/
public CallChainDemoThree(AbstractCallChain nextChain) {
super(nextChain);
}
@Override
public Object process(Object param) {
System.out.println("执行CallChainDemoThree");
return null;
}
}
编写运行类
public class AbstractCallChainRunner {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1,"priv.yxp.elegance.test.prioritychainofresponsibility.chain.CallChainDemoOne");
map.put(2,"priv.yxp.elegance.test.prioritychainofresponsibility.chain.CallChainDemoTwo");
map.put(3,"priv.yxp.elegance.test.prioritychainofresponsibility.chain.CallChainDemoThree");
PriorityChainWrapper wrapper = new PriorityChainWrapper(map);
wrapper.doChain("测试");
}
}
运行结果为
执行CallChainDemoThree
执行CallChainDemoTwo
执行CallChainDemoOne
总结
priorityChainMap可以配置在数据库或者其他地方,可以动态控制调用的类和优先级,可以自定义自己的入参对象和出参对象用于判断当前调用链是否执行成功。
欢迎关注我的公众号
枝丫技术坊