引言
这是设计模式专栏的第二篇文章,在这个专栏里面会讲到我们在开发中经常使用的设计模式,我会用心将它们解析,然后讲给你们听,如果感兴趣可以持续关注这个专栏❤️
这次我们要讲的是责任链模式,这是在实际的开发中非常常用的软件设计模式,为什么呢?又得讲到那个非常经典的例子了,你是一个程序员,今天临时起意想要暂时远离一下这种枯燥生活,去旅游或者休息,于是你在OA系统提起了七天的假期申请,需要流程审批。首先你的组长会看到这个审批,但是他没有权限审批七天的假期,又到你的Leader审批,但是他也同样没有这么大的权限,这个审批一直流转,终于流到了有能力审批七天假期的部门大佬....
这种像一个链子一样的,允许多个对象处理请求,请求会沿着建造好的链子前进,一直达到有能力处理的节点,这种就是责任链模式。
责任链模式的定义😯
上面说了这么多,那么责任链模式定义到底是什么呢?
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象有机会处理请求,从而避免请求的发送者和接收者之间的耦合。请求沿着一条链传递,直到有一个对象处理它为止。
责任链模式的核心思想
- 将多个处理器连接成一条链。
- 请求从链的一端发起,沿着链传递,每个节点都有机会处理请求或将其传递给下一个节点。
- 如果当前节点不能处理该请求,则将请求转发给下一个节点。
使用场景
- 请求的处理有多个步骤或条件,例如审批流程、权限控制等。
- 请求的处理者不确定是谁,希望动态指定。
- 解耦请求发送者和处理者,使系统更灵活、可扩展。
结构组成
- Handler(抽象处理者) :定义处理请求的接口,通常包含一个指向下一个处理者的引用。
- ConcreteHandler(具体处理者) :实现处理逻辑。可以决定是否处理请求或将请求传给下一个处理者。
- Client(客户端) :创建处理链并提交请求。
责任链模式的具体使用😎
上面的定义太枯燥了,直接来看怎么使用责任链模式吧,这里笔者选取了自己最熟悉也是觉得最好用的实现方式来给大家看看,如果有佬觉得还有更好的实现方式欢迎在评论区留言或者私信交流🤓
ps:笔者只展示最主要的部分,请大家集中注意力关注主要部分
责任链装载接口
这里是责任链的装载接口,appendNext负责添加下一个责任链节点,next()负责返回责任链中的下一个节点
java
public interface ILogicChainArmory {
ILogicChain appendNext(ILogicChain next);
ILogicChain next();
}
责任链接口
这个责任链接口,就是对应的节点类型,logic方法就是每个具体节点都要实现的逻辑
java
public interface ILogicChain extends ILogicChainArmory{
DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId);
}
责任链抽象类
由于ILogicChain extends ILogicChainArmory,实现子接口的类也必须提供这些方法的具体实现。
但是因为AbstractLogicChain是抽象类,所以实现任意一部分就行了(甚至可以不实现),这里我们实现责任链的装载方法,让具体责任链实现节点类只需要负责实现具体逻辑logic就行,不需要关注其他多余实现(设计模式的各司其职)
java
public abstract class AbstractLogicChain implements ILogicChain{
private ILogicChain next;
@Override
public ILogicChain appendNext(ILogicChain next) {
this.next = next;
return next;
}
@Override
public ILogicChain next() {
return next;
}
责任链具体节点(黑名单节点示例)
这里是一个责任链的具体节点,继承了上面的抽象类,实现具体逻辑即可
java
@Slf4j
@Component("rule_blacklist")
public class BackListLogicChain extends AbstractLogicChain {
@Resource
private IStrategyRepository repository;
@Override
public DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId) {
//获得对应策略,黑名单的用户配置和奖品配置
String ruleValue = repository.queryStrategyRuleValue(strategyId, ruleModel());
String[] splitRuleValue = ruleValue.split(Constants.COLON);
Integer awardId = Integer.parseInt(splitRuleValue[0]);
String[] userBlackIds = splitRuleValue[1].split(Constants.SPLIT);
// 黑名单判断
for (String userBlackId : userBlackIds) {
if (userId.equals(userBlackId)) {
return DefaultChainFactory.StrategyAwardVO.builder()
.awardId(awardId)
.logicModel(ruleModel())
.build();
}
}
// 过滤其他责任链
return next().logic(userId, strategyId);
}
}
默认节点
这是一个默认的责任链节点,代表请求最终一定可以处理
java
@Slf4j
@Component("default")
public class DefaultLogicChain extends AbstractLogicChain {
@Resource
protected IStrategyDispatch strategyDispatch;
@Override
public DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId) {
Integer awardId = strategyDispatch.getRandomAwardId(strategyId);
return DefaultChainFactory.StrategyAwardVO.builder()
.awardId(awardId)
.logicModel(ruleModel())
.build();
}
}
责任链工厂
这里是责任链工厂,负责装载责任链。通过Spring的依赖注入,我们可以很方便的得到所有实现了ILogicChain的具体实现类,通过一个map类型来承载(只有打上注解@Component
的具体节点实现类才可以被Spring的bean容器管理)
java
@Service
public class DefaultChainFactory {
private final Map<String, ILogicChain> logicChainGroup;
private final IStrategyRepository repository;
public DefaultChainFactory(Map<String, ILogicChain> logicChainGroup, IStrategyRepository repository) {
this.logicChainGroup = logicChainGroup;
this.repository = repository;
}
public ILogicChain openLogicChain(Long strategyId) {
StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId);
//获得该策略对应的ruleModels
String[] ruleModels = strategy.ruleModels();
// 如果未配置策略规则,则只装填一个默认责任链
if (null == ruleModels || 0 == ruleModels.length) return logicChainGroup.get("default");
// 按照配置顺序装填用户配置的责任链
ILogicChain logicChain = logicChainGroup.get(ruleModels[0]);
ILogicChain current = logicChain;
for (int i = 1; i < ruleModels.length; i++) {
ILogicChain nextChain = logicChainGroup.get(ruleModels[i]);
current = current.appendNext(nextChain);
}
// 责任链的最后装填默认责任链
current.appendNext(logicChainGroup.get("default"));
return logicChain;
}
}
测试使用😈
通过openLogicChain我们就可以获得责任链的头节点,请求放进去就可以在里面流转,最终一定会被处理
java
@Test
public void test_LogicChain_rule_blacklist() {
ILogicChain logicChain = defaultChainFactory.openLogicChain(100001L);
DefaultChainFactory.StrategyAwardVO awardId = logicChain.logic("user001", 100001L);
log.info("测试结果:{}", awardId);
}
总结❤️
这就是责任链模式的解析,我们下次再见。
如果你看了这篇文章有收获可以点赞+关注+收藏🤩,这是对笔者更新的最大鼓励!如果你有更多方案或者文章中有错漏之处,请在评论区提出帮助笔者勘误,祝你拿到更好的offer!