最近业务上有这个需求:给服务顾问分配服务订单(一个服务订单就是对应的一个资源客户)时,需要层层过滤规则。具体的有如下规则:1、顾问性别规则;2、服务顾问分配数上限规则;3、收入规则;4、本地优先规则;5、顾问分配间隔规则(即一个顾问在间隔8小时内只能被分一个单子);
具体操作就是:首先查询出满足条件的所有服务顾问id,放到一个数组里面(下文统称ids),然后依次通过上述规则的过滤判断,把过滤后的ids传给下一个规则里面过滤,直到最后一个规则过滤完成,返回最终的ids;
在这里面,我想到了设计模式-责任链模式;
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,用于将请求的发送者和接收者解耦,并允许多个对象都有机会处理该请求。在责任链模式中,请求沿着一个由多个对象组成的链传递,直到有一个对象能够处理请求为止。
定义责任链模式的关键思想是:将处理请求的对象组织成一个链条,并将请求沿着链条传递,直到有一个对象能够处理它为止。每个处理对象都有一个指向下一个处理对象的引用,形成一个链式结构。
责任链模式的定义包括以下关键要点:
发送者与接收者解耦:责任链模式将发送者和接收者解耦,使得发送者无需知道请求将由哪个具体接收者处理,而接收者也无需知道请求的发送者是谁。
1、多个对象组成链:责任链模式由多个对象组成一条链,每个对象都有机会处理请求。这些对象被称为处理者(Handler)。
2、处理者的责任:每个处理者都有一个对下一个处理者的引用,形成了一个链条。当请求到达一个处理者时,该处理者可以选择处理请求或将其传递给下一个处理者。
3、动态的请求处理流程:责任链模式允许在运行时动态地改变请求的处理流程。可以根据实际情况来配置和调整链条中的处理者顺序。
4、责任链模式的核心思想是将请求沿着链条传递,直到有一个处理者能够处理它为止。这种模式适用于存在多个处理者处理同一类型请求的情况,而发送者无法确定哪个处理者将处理请求,或者希望动态地指定处理者的情况。
通过使用责任链模式,可以实现请求的动态处理、解耦发送者和接收者、以及提高代码的灵活性和可扩展性。
具体代码实现:
我为每个规则定义了一个对象,然后统一继承一个父对象,定义一个链式对象(AcMatchCalcHardRuleChain),把每个对象都添加到链式中(通过add方法)
public List<String> screenDacTAgentIds(CustTagMsgVo custTag, CustBusinessBean cbb, List<String> agentIds) {
AcMatchCalcHardRuleChain hardChain = new AcMatchCalcHardRuleChain();
hardChain.add(acMatchAgentGenderRule).add(acMatchNumRule).add(acMatchCDRule).add(acMatchAgentLocalRule).add(acMatchTimeRule);
return hardChain.doFilter(custTag,cbb,agentIds);
}
链式对象的具体实现如下:
public class AcMatchCalcHardRuleChain {
List<AcMatchCalcHardRule> filters = new ArrayList<>();
int index = 0;
public AcMatchCalcHardRuleChain add(AcMatchCalcHardRule filter){
filters.add(filter);
return this;
}
public List<String> doFilter(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String> agentIds){
if(index == filters.size()) {
return agentIds;
}
AcMatchCalcHardRule f = filters.get(index);
index ++;
// 这里会调用具体的规则对象的实现方法
List<String> info = f.doFilter(custTag,businessBean,agentIds, this);
if(null == info){
return null;
}
return info;
}
}
如上图所示:acMatchAgentGenderRule、acMatchNumRule、acMatchCDRule、
acMatchAgentLocalRule、acMatchTimeRule 对应的是每一个规则对象,他们都继承一个
AcMatchCalcHardRule (硬性规则),然后AcMatchCalcHardRule 继承了AcMatchCalcRule 匹配计算规则(最终父规则),上图中的f.doFilter方法中的 this 就是链式对象,指向下一个处理对象的引用
我们随机看一个具体的规则对象的doFilter实现方法
@Override
public List<String> rule(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String> agentIds) {
List<String> thisAgentIds = new ArrayList<>(agentIds);
if(null == custTag.getHopeAgentGender()){
return thisAgentIds;
}
if(custTag.getHopeAgentGender() == 1 || custTag.getHopeAgentGender() == 2){
thisAgentIds = agentMongoDao.findByIdAndGender(thisAgentIds,custTag.getHopeAgentGender());
}
return thisAgentIds;
}
@Override
public List<String> doFilter(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String> agentIds, AcMatchCalcHardRuleChain chain ){
log.info("AcMatchAgentGenderRule 处理前:{}",agentIds.size());
List<String> thisAgentIds = rule(custTag,businessBean,agentIds);
if(EmptyUtils.isEmpty(thisAgentIds)){
log.info("AcMatchAgentGenderRule 处理后:{}",0);
return null;
}
log.info("AcMatchAgentGenderRule 处理后:{}",thisAgentIds.size());
return chain.doFilter(custTag,businessBean,thisAgentIds);
}
以下是一个具体的对象规则的详细代码(AcMatchAgentGenderRule 是性别规则)
@Slf4j
@Component("acMatchAgentGenderRule")
public class AcMatchAgentGenderRule implements AcMatchCalcHardRule {
@Autowired
private AgentMongoDao agentMongoDao;
@Override
public List<String> calc(CustTagMsgVo custTag, CustBusinessBean businessBean, List agentIds) {
return rule(custTag, businessBean, agentIds);
}
@Override
public List<String> rule(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String> agentIds) {
List<String> thisAgentIds = new ArrayList<>(agentIds);
if(null == custTag.getHopeAgentGender()){
return thisAgentIds;
}
if(custTag.getHopeAgentGender() == 1 || custTag.getHopeAgentGender() == 2){
thisAgentIds = agentMongoDao.findByIdAndGender(thisAgentIds,custTag.getHopeAgentGender());
}
return thisAgentIds;
}
@Override
public List<String> doFilter(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String
public interface AcMatchCalcHardRule extends AcMatchCalcRule {
AcRuleTypeEnum rule = AcRuleTypeEnum.hard;
List<String> rule(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String> agentIds);
List<String> doFilter(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String> agentIds, AcMatchCalcHardRuleChain chain );
}
public interface AcMatchCalcRule {
List<String> calc(CustTagMsgVo custTag, CustBusinessBean businessBean, List<String> agentIds);
}