在软件开发中,我们经常需要应用一组规则或条件来过滤和处理数据。使用传统的 if 和 else 条件管理这些规则可能会变得繁琐且难以维护。规则引擎提供了一种更灵活、更有条理的方法来定义和执行这些规则。在本文中,我们将探讨如何使用 Java 函数式编程原理在 Spring Boot 项目中构建一个简单的规则引擎。
什么是规则引擎?
规则引擎是一个专家系统程序,它对输入数据运行规则,如果任何条件匹配,则执行相应的操作。
规则引擎负责管理一组规则,并将它们应用于一组对象。它根据定义的规则过滤对象并返回过滤结果。
案例
在这个应用程序中,首先我将创建一个UserController.java类并创建一个返回用户列表的Rest端点。
import com.example.spring_boot_rule_engine_demo.model.User; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.GetMapping; import java.util.ArrayList; import java.util.List;
@RestController @RequestMapping("/user") public class UserController { @GetMapping public List<User> getAllUser(){ return userData(); }
private List<User> userData() { List<User> users = new ArrayList<>(); User user1 = new User("sumit", 33); User user2 = new User("agam", 13); User user3 = new User("mohit", 23); User user4 = new User("kailash", 43); users.add(user1); users.add(user2); users.add(user3); users.add(user4); return users; }
}
|
现在,我们要求只获取年龄大于 30 岁、姓名以 sum 开头的用户。
因此,现在我们需要创建两条规则,并在向客户端返回响应前应用这两条规则。
定义规则:
首先,我们将使用一个名为 Rule 的枚举来定义规则。枚举中的每条规则都代表我们要评估的特定条件或标准。
import com.example.spring_boot_rule_engine_demo.model.User;
import java.util.function.Predicate;
public enum Rule implements TestRule {
AGE_GREATER_THAN_30(user -> user.getAge() > 30), NAME_STARTS_WITH_SUM(user -> user.getName().startsWith("sum"));
private final Predicate<User> predicate;
Rule(Predicate<User> predicate) { this.predicate = predicate; }
public Predicate<User> getPredicate() { return predicate; } }
|
让我创建一个 TestRule 接口来定义不需要实现的方法。
import java.util.function.Predicate;
public interface TestRule { <T> Predicate<T> getPredicate(); }
|
创建自己的规则引擎:
接下来,我们创建 RuleEngine 类。该类将处理规则的管理和执行。它维护一个规则列表,并提供添加新规则和根据这些规则过滤对象的方法。
实现过滤逻辑
在 RuleEngine 类的过滤方法中,我们遍历对象列表,并使用 Java 8 Stream API 中的 allMatch 方法应用每条规则。该方法会检查给定对象是否通过了所有规则。如果所有规则都通过,我们就会将该对象添加到过滤列表中。
import com.example.spring_boot_rule_engine_demo.rule.TestRule;
import java.util.ArrayList; import java.util.List;
public class RuleEngine<T> { private List<TestRule> rules;
public RuleEngine() { this.rules = new ArrayList<>(); }
public void addRule(TestRule rule) { rules.add(rule); }
public List<T> filter(List<T> items) { List<T> filteredItems = new ArrayList<>(); for (T item : items) { if (rules.stream().allMatch(rule -> rule.getPredicate().test(item))) { filteredItems.add(item); } } return filteredItems; } } public class User {
private String name; private int age;
public User(String name, int age) { this.name = name; this.age = age; }
public User() {
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; } }
|
在 UserController.java 类中创建的获取所有用户 API 中,我们演示了规则引擎的用法。我们创建了一个用户对象列表,并用两条规则初始化了规则引擎:AGE_GREATER_THAN_30 和 NAME_STARTS_WITH_SUM。然后,我们调用规则引擎的过滤器方法,并传递用户对象列表。规则引擎会对每个用户应用规则,并返回过滤后的列表。
最后,我们遍历过滤后的列表,返回符合指定规则的用户列表。
import com.example.spring_boot_rule_engine_demo.engine.RuleEngine; import com.example.spring_boot_rule_engine_demo.model.User; import com.example.spring_boot_rule_engine_demo.rule.Rule; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.GetMapping; import java.util.ArrayList; import java.util.List;
@RestController @RequestMapping("/user") public class UserController { @GetMapping public List<User> getAllUser(){ RuleEngine<User> ruleEngine = new RuleEngine<>(); ruleEngine.addRule(Rule.AGE_GREATER_THAN_30); ruleEngine.addRule(Rule.NAME_STARTS_WITH_SUM); List<User> filteredUser = ruleEngine.filter(userData()); return filteredUser; }
private List<User> userData() { List<User> users = new ArrayList<>(); User user1 = new User("sumit", 33); User user2 = new User("agam", 13); User user3 = new User("mohit", 23); User user4 = new User("kailash", 43); users.add(user1); users.add(user2); users.add(user3); users.add(user4); return users; }
}
|
源码:Github