当前位置:网站首页>Still writing a lot of if to judge? A rule executor kills all if judgments in the project
Still writing a lot of if to judge? A rule executor kills all if judgments in the project
2022-07-29 00:26:00 【Fat technology house】
Business scenario
Recently, I received a small demand in the company , You need to expand the existing trial user application rules . Our scenario is roughly as follows :
if ( Whether overseas users ) {
return false;
}
if ( Billing user ) {
return false;
}
if ( Unpaid users && No longer in service ) {
return false
}
if ( Transfer to introduce the user || Paying users || Push users ) {
return true;
}
According to the above conditions, we can come to the conclusion that :
Our main process is mainly based on and perhaps or The relationship between .
If there is a mismatch , In fact, our follow-up process does not need to be implemented , It needs to have a short circuit function .
For the current situation , If I change it on the original basis , Just pay a little attention to solving the problem that the demand is not very big , But the maintainability is very poor .
After weighing in the back , I decided to refactor this part .
Rule executor
For this demand , I first sorted out the general design of our rule actuator , Then I designed a V1 Version to share with you , If everyone has such a case You can share messages with me , The following part is mainly the design and implementation process code.
Design of rule executor

Abstract rules and implement rules
// Business data
@Data
public class RuleDto {
private String address;
private int age;
}
// Rule abstraction
public interface BaseRule {
boolean execute(RuleDto dto);
}
// Rule templates
public abstract class AbstractRule implements BaseRule {
protected <T> T convert(RuleDto dto) {
return (T) dto;
}
@Override
public boolean execute(RuleDto dto) {
return executeRule(convert(dto));
}
protected <T> boolean executeRule(T t) {
return true;
}
}
// Specific rules - Example 1
public class AddressRule extends AbstractRule {
@Override
public boolean execute(RuleDto dto) {
System.out.println("AddressRule invoke!");
if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) {
return true;
}
return false;
}
}
// Specific rules - Example 2
public class NationalityRule extends AbstractRule {
@Override
protected <T> T convert(RuleDto dto) {
NationalityRuleDto nationalityRuleDto = new NationalityRuleDto();
if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) {
nationalityRuleDto.setNationality(MATCH_NATIONALITY_START);
}
return (T) nationalityRuleDto;
}
@Override
protected <T> boolean executeRule(T t) {
System.out.println("NationalityRule invoke!");
NationalityRuleDto nationalityRuleDto = (NationalityRuleDto) t;
if (nationalityRuleDto.getNationality().startsWith(MATCH_NATIONALITY_START)) {
return true;
}
return false;
}
}
// Constant definition
public class RuleConstant {
public static final String MATCH_ADDRESS_START= " Beijing ";
public static final String MATCH_NATIONALITY_START= " China ";
}
Actuator build
public class RuleService {
private Map<Integer, List<BaseRule>> hashMap = new HashMap<>();
private static final int AND = 1;
private static final int OR = 0;
public static RuleService create() {
return new RuleService();
}
public RuleService and(List<BaseRule> ruleList) {
hashMap.put(AND, ruleList);
return this;
}
public RuleService or(List<BaseRule> ruleList) {
hashMap.put(OR, ruleList);
return this;
}
public boolean execute(RuleDto dto) {
for (Map.Entry<Integer, List<BaseRule>> item : hashMap.entrySet()) {
List<BaseRule> ruleList = item.getValue();
switch (item.getKey()) {
case AND:
// If it is and Relationship , Synchronous execution
System.out.println("execute key = " + 1);
if (!and(dto, ruleList)) {
return false;
}
break;
case OR:
// If it is or Relationship , Parallel execution
System.out.println("execute key = " + 0);
if (!or(dto, ruleList)) {
return false;
}
break;
default:
break;
}
}
return true;
}
private boolean and(RuleDto dto, List<BaseRule> ruleList) {
for (BaseRule rule : ruleList) {
boolean execute = rule.execute(dto);
if (!execute) {
// and Relationship matching failed once , return false
return false;
}
}
// and All relationships match successfully , return true
return true;
}
private boolean or(RuleDto dto, List<BaseRule> ruleList) {
for (BaseRule rule : ruleList) {
boolean execute = rule.execute(dto);
if (execute) {
// or If the relationship matches one, it returns true
return true;
}
}
// or If none of the relationships match, it returns false
return false;
}
}
The call of the actuator
public class RuleServiceTest {
@org.junit.Test
public void execute() {
// Rule executor
// advantage : Relatively simple , Each rule can be independent , Put the rules , data , The actuator is disassembled , The caller is regular
// shortcoming : Data depends on common transport objects dto
//1. Define the rules init rule
AgeRule ageRule = new AgeRule();
NameRule nameRule = new NameRule();
NationalityRule nationalityRule = new NationalityRule();
AddressRule addressRule = new AddressRule();
SubjectRule subjectRule = new SubjectRule();
//2. Construct the required data create dto
RuleDto dto = new RuleDto();
dto.setAge(5);
dto.setName(" Zhang San ");
dto.setAddress(" Beijing ");
dto.setSubject(" mathematics ");;
//3. Build and execute by chaining calls rule execute
boolean ruleResult = RuleService
.create()
.and(Arrays.asList(nationalityRule, nameRule, addressRule))
.or(Arrays.asList(ageRule, subjectRule))
.execute(dto);
System.out.println("this student rule execute result :" + ruleResult);
}
}
summary
Advantages and disadvantages of rule executors
advantage :
Relatively simple , Each rule can be independent , Put the rules , data , The actuator is disassembled , The caller is regular ;
I am here Rule Template class convert Method to convert parameters so that , For specific rule The required scene data is provided .
shortcoming :
Up and down rule There's data dependence , If you modify the public transport object directly dto This design is not very reasonable , It is recommended to build the data in advance .
边栏推荐
猜你喜欢

Html+css+php+mysql realize registration + login + change password (with complete code)

Control fillet stroke materialshapedrawable

Develop effective Tao spell

【微服务~Nacos】Nacos服务提供者和服务消费者

#{}和${}的区别

Install mysql5.7 under Linux, super detailed complete tutorial, and cloud MySQL connection

Why is it so difficult for the SEC to refuse the application for transferring gray-scale GBTC to spot ETF? What is the attraction of ETF transfer?

Eye of depth (18) -- partial derivative

Dynamic programming problem (6)

Dynamic programming (V)
随机推荐
IDEA报错Error running ‘Application‘ Command line is too long解决方案
Do like and in indexes in MySQL go
时间序列统计分析
Applet waterfall flow, upload pictures, simple use of maps
Summary: the difference between pod and container
MySQL stored procedure
Event extraction and documentation (2008-2017)
“Method Not Allowed“,405问题分析及解决
vulnhub:SolidState
@Detailed explanation of the use of transactional annotation
Eye of depth (18) -- partial derivative
软考 --- 数据库(4)SQL语句
分布式限流 redission RRateLimiter 的使用及原理
动态规划问题(四)
vulnhub:Sar
Recursion / backtracking (middle)
动态规划问题(六)
Alibaba Code代码索引技术实践:为Code Review提供本地IDE的阅读体验
Camera Hal OEM模块 ---- cmr_preview.c
Newscenter, advanced area of attack and defense world web masters