Design and Implementation of a Java Rule Engine

This article explains how to extend a trial‑user application rule by designing a flexible Java rule engine, detailing the logical conditions, abstract and concrete rule classes, a builder service supporting AND/OR composition, and discussing its advantages and drawbacks.

Architect's Guide
Architect's Guide
Architect's Guide
Design and Implementation of a Java Rule Engine

To handle a new requirement for extending trial‑user application rules, the author first outlines the logical conditions (e.g., reject overseas users, fraudulent users, unpaid users outside service hours, and accept referred, paid, or internally recommended users) using simple boolean checks.

if (是否海外用户) { return false; }<br/>if (刷单用户) { return false; }<br/>if (未付费用户 && 不再服务时段) { return false; }<br/>if (转介绍用户 || 付费用户 || 内推用户) { return true; }

The design introduces a rule executor that can combine rules with AND/OR logic and supports short‑circuit evaluation. An abstract base class provides a conversion hook and a template execution method, while concrete rule classes implement specific checks such as address prefix and nationality.

// 业务数据<br/>@Data<br/>public class RuleDto {<br/>  private String address;<br/>  private int age;<br/>}<br/><br/>// 规则抽象<br/>public interface BaseRule {<br/>  boolean execute(RuleDto dto);<br/>}<br/><br/>// 规则模板<br/>public abstract class AbstractRule implements BaseRule {<br/>  protected <T> T convert(RuleDto dto) { return (T) dto; }<br/>  @Override<br/>  public boolean execute(RuleDto dto) { return executeRule(convert(dto)); }<br/>  protected <T> boolean executeRule(T t) { return true; }<br/>}<br/><br/>// 具体规则‑例子1<br/>public class AddressRule extends AbstractRule {<br/>  @Override<br/>  public boolean execute(RuleDto dto) {<br/>    System.out.println("AddressRule invoke!");<br/>    if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) { return true; }<br/>    return false;<br/>  }<br/>}<br/><br/>// 具体规则‑例子2<br/>public class NationalityRule extends AbstractRule {<br/>  @Override<br/>  protected <T> T convert(RuleDto dto) {<br/>    NationalityRuleDto nrDto = new NationalityRuleDto();<br/>    if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) { nrDto.setNationality(MATCH_NATIONALITY_START); }<br/>    return (T) nrDto;<br/>  }<br/>  @Override<br/>  protected <T> boolean executeRule(T t) {<br/>    NationalityRuleDto nrDto = (NationalityRuleDto) t;<br/>    if (nrDto.getNationality().startsWith(MATCH_NATIONALITY_START)) { return true; }<br/>    return false;<br/>  }<br/>}<br/><br/>// 常量定义<br/>public class RuleConstant {<br/>  public static final String MATCH_ADDRESS_START = "北京";<br/>  public static final String MATCH_NATIONALITY_START = "中国";<br/>}

The RuleService class stores rule lists keyed by AND (1) or OR (0) and provides a fluent API to add rule groups and execute them against a RuleDto. The execution iterates over each group, applying short‑circuit logic appropriate to the logical operator.

public class RuleService {<br/>  private Map<Integer, List<BaseRule>> hashMap = new HashMap<>();<br/>  private static final int AND = 1;<br/>  private static final int OR = 0;<br/><br/>  public static RuleService create() { return new RuleService(); }<br/><br/>  public RuleService and(List<BaseRule> ruleList) { hashMap.put(AND, ruleList); return this; }<br/>  public RuleService or(List<BaseRule> ruleList) { hashMap.put(OR, ruleList); return this; }<br/><br/>  public boolean execute(RuleDto dto) {<br/>    for (Map.Entry<Integer, List<BaseRule>> item : hashMap.entrySet()) {<br/>      List<BaseRule> ruleList = item.getValue();<br/>      switch (item.getKey()) {<br/>        case AND:<br/>          System.out.println("execute key = " + 1);<br/>          if (!and(dto, ruleList)) return false;<br/>          break;<br/>        case OR:<br/>          System.out.println("execute key = " + 0);<br/>          if (!or(dto, ruleList)) return false;<br/>          break;<br/>        default: break;<br/>      }<br/>    }<br/>    return true;<br/>  }<br/><br/>  private boolean and(RuleDto dto, List<BaseRule> ruleList) {<br/>    for (BaseRule rule : ruleList) {<br/>      if (!rule.execute(dto)) return false;<br/>    }<br/>    return true;<br/>  }<br/><br/>  private boolean or(RuleDto dto, List<BaseRule> ruleList) {<br/>    for (BaseRule rule : ruleList) {<br/>      if (rule.execute(dto)) return true;<br/>    }<br/>    return false;<br/>  }<br/>}

A test class demonstrates usage: instantiate concrete rules, build a

RuleDto**, set sample data, and invoke the service with an AND group followed by an OR group.</p><p><code>public class RuleServiceTest {<br/>  @org.junit.Test<br/>  public void execute() {<br/>    AgeRule ageRule = new AgeRule();<br/>    NameRule nameRule = new NameRule();<br/>    NationalityRule nationalityRule = new NationalityRule();<br/>    AddressRule addressRule = new AddressRule();<br/>    SubjectRule subjectRule = new SubjectRule();<br/><br/>    RuleDto dto = new RuleDto();<br/>    dto.setAge(5);<br/>    dto.setName("张三");<br/>    dto.setAddress("北京");<br/>    dto.setSubject("数学");<br/><br/>    boolean ruleResult = RuleService.create()<br/>        .and(Arrays.asList(nationalityRule, nameRule, addressRule))<br/>        .or(Arrays.asList(ageRule, subjectRule))<br/>        .execute(dto);<br/>    System.out.println("this student rule execute result :" + ruleResult);<br/>  }<br/>}

The author concludes with pros and cons: the approach is simple and modular, allowing independent rule development and clear separation of data, rule, and executor, but it introduces data coupling via a shared DTO, suggesting pre‑construction of immutable data structures for better design.

Overall, the article provides a practical example of building a rule engine in Java, illustrating design choices, implementation details, and considerations for maintainability.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javarule engineCode Example
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.