在Java中用規則引擎模式替代ifelse - Vitali

banq發表於2021-12-06

規則引擎模式:這種模式的本質是if - else ,拆分if - else每個分支到規則類中,然後,主規則引擎類將儲存所有規則並找到與客戶端請求匹配的規則。

定義規則類
為了確保所有規則類都實現相同的方法,讓我們定義一個每個類都將實現的介面:

public interface AncestorRule {
  Optional<AncestorResult> evaluate(String selector);
}

接下來,讓我們定義第一個規則類。該類將儲存if - else分支中定義的邏輯:

public class AncestorWithClassRule implements AncestorRule {

  @Override
  public Optional<AncestorResult> evaluate(String selector) {
    if (isCssClass(selector)) {
      String xpath = format(
        "ancestor::*[contains(concat(' ', normalize-space(@class), ' '), ' %s ')][%s]",
        selector.substring(1)
      );
      return Optional.of(new AncestorResult(xpath));
    }
    return Optional.empty();
  }
}

 isCssClass()判斷如果它是一個 CSS 類,則會構建一個 XPath 表示式並將其作為一i個Optional 返回。
這個規則類乾淨、簡短、易於理解。一次編寫,不需要經常修改,除非規則的業務邏輯有更新。
我們以同樣的方式定義其他規則。驗證輸入是否與給定條件匹配,構建並返回相應的 XPath 表示式。否則,結果為空。
 

規則結果
上面的程式碼使用了AncestorResult. 這個類的目的是包裝成功評估的結果。這個類如下所示:

public class AncestorResult {

  private final String value;

  public AncestorResult(String value) {
    this.value = value;
  }

  public String getValue() {
    return value;
  }
}

只是我們透過建構函式設定的一個類欄位並使用 getter 訪問它。
 

規則引擎類
現在,讓我們最終進入包含規則引擎邏輯的類。

public class AncestorRuleEngine {

    private static final List<AncestorRule> rules = Arrays.asList(
        new AncestorWithTagRule(),
        new AncestorWithClassRule(),
        new AncestorWithAttributeRule(),
        new AncestorWithAttributeAndValueRule()
    );

    public AncestorResult process(String selector) {
        return rules
            .stream()
            .map(rule -> rule.evaluate(selector))
            .flatMap(optional -> optional.map(Stream::of).orElseGet(Stream::empty))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("Selector does not match any rule"));
    }
}

在這個類中做的第一件事是一個適用於這個域的所有規則的靜態列表。如果我們有一個新規則——我們實現一個新類並將它新增到這個規則列表中。
第二件事是跨所有規則處理客戶端的輸入。它流式傳輸規則列表,評估每個規則。規則的第一個非空結果被返回給客戶端。否則,規則引擎將丟擲異常。
前一個map()函式返回一個可選的流。然後, flatMap()將空 Optionals 流轉換為空流。否則,將一個非空的 AncestorResults 流封裝到 Optional 中。該構造與 Java 8 相容並且看起來很冗長。幸運的是,從 Java 9 開始,這可以簡化。
 

規則引擎的使用
現在,當我們實現了所有或規則時,規則引擎就定義好了,讓我們看看如何呼叫和使用這個引擎。

public class ClientSideThatCallsTheRuleEngine {

    public void executeClientCode() {
        // some executions

        AncestorRuleEngine ruleEngine = new AncestorRuleEngine();
        String xpath = ruleEngine.process(selector).getValue();
        
        // other executions
    }



它是如此簡單。例項化規則引擎。傳入客戶端的輸入,得到結果。它乾淨、簡短且精確。我們隱藏了驗證輸入、構建相應結果、處理它的所有低階邏輯。將其與具有多個if - else分支的直接方法進行比較。我們新增的邏輯越多,這個if - else怪物就會成長得越多。

 

相關文章