一個擴展搜索API的優化過程

概述

API 是一個服務的門面,就像衣裝是人的形象同樣。java

優雅的 API 設計,能讓業務方使用起來倍兒爽,提高開發效率,下降維護成本;糟糕的 API 設計,則讓業務方遭心,陷入混沌。優化

本文將展現一個擴展搜索 API 的優化過程,從中也能夠學到一些東西。

ui

現狀

找一個上游工程的擴展搜索代碼以下:this

extendKeywords.add((EsCondition) ConditionFactory.in("order_tags", Arrays.asList("IS_XXX_ORDER")));
extendKeywords.add(new EsCondition("goods_title", Op.match, new Match(goodsTitle, "100%")));

啊啊,真是醜死了 ! 爲何呢 ?設計

  • 強制類型轉換。 讓業務方寫強制類型轉換,簡直是讓業務方來遭罪的 ! 這 API 設計簡直了 !
  • 暴漏底層細節。 讓業務方 new EsCondition ,不只是暴漏底層細節,還很難看!
  • 不方便的傳值。 爲了傳一個 in 的數值,須要寫個 Arrays.asList(e) !
  • 遍及的 EsCondition 。 因爲 API 設計的很裸,致使上游工程處處瀰漫着 EsCondition 的煙霧。

emmm... 實際上是我設計的 API 造的孽 ! 解鈴還須繫鈴人。

code

優化過程

工廠方法

這種硬的 new EsConditon ,徹底能夠經過工廠方法和方法重載來消除。此外,爲了收攏擴展搜索條件的構建,能夠構建一個專門的 ExtendSearchParam 。對象

public class ExtendSearchParam implements Serializable {
  private static final long serialVersionUID = 2824767430430079287L;

  private List<EsCondition> extendConditions = new ArrayList<>();

  public ExtendSearchParam addEq(String field, Object value) {
    extendConditions.add(new EsCondition(field, Op.eq, value));
    return this;
  }

  public ExtendSearchParam addIn(String field, Object... list) {
    extendConditions.add(new EsCondition(field, Op.in, list));
    return this;
  }

  public ExtendSearchParam addRange(String field, long gte, long lte) {
    extendConditions.add(new EsCondition(field, Op.range, new Range(gte, lte)));
    return this;
  }

  public ExtendSearchParam addMatch(String field, String query) {
    extendConditions.add(new EsCondition(field, Op.match, new Match(query, "100%")));
    return this;
  }

  public ExtendSearchParam addMatch(String field, String query, String match) {
    extendConditions.add(new EsCondition(field, Op.match, new Match(query, match)));
    return this;
  }
}

這裏借鑑了 Builder 模式,可以鏈式地構建擴展搜索條件。這樣,業務方就能夠舒心地寫上:開發

extendSearchParam.addIn(ORDER_TAGS, "IS_XXX_ORDER").addMatch("goods_title", goodsTitle);

沒有了類型強制轉換,沒有了暴漏底層細節,沒有了不方便的傳值,還能夠一直 add 下去, 世界多美好 !

get

攔路虎

很快,就遇到了攔路虎:it

private List<EsCondition> dealOrderSourceCondition(String orderSource) {        
     List<EsCondition> result = new ArrayList();
     result.add(new EsCondition(TYPE_ENTRANCE, Op.eq, "wsc"));
     result.add(new EsCondition(TYPE_PLATFORM, Op.eq, "wx"));
     return result;
}

emmm , 寫這個方法的小夥伴也是好意,封裝一個方法來構建訂單來源擴展條件也是好意。不過這給API 重構帶來了一點點小小的障礙。

怎麼重寫這一段呢 ? 第一想到的是,在 dealOrderSourceCondition 的方法裏額外增長一個參數 ExtendSearchParam ,傳進去,修改它。也能達到目地。可是,—— 破壞了「不可變」原則。 不可變原則要求,儘量避免修改入參。修改入參這種行爲,很容易致使不起眼的 BUG ,若是在關鍵流程中作這個事情,有可能致使故障。有線上教訓的。

怎麼辦呢 ? 又不能修改 dealOrderSourceCondition 的入參,又要把這個方法的擴展搜索條件合併到已有的擴展搜索對象中。

有一種辦法 ! 合併擴展搜索對象 ExtendSearchParam 。 這樣,ExtendSearchParam 須要支持一個合併操做:

public ExtendSearchParam merge(ExtendSearchParam extendSearchParam) {
    if (extendSearchParam != null && extendSearchParam.has()) {
      extendConditions.addAll(extendSearchParam.getUnmodifiedExtendSearch());
    }
    return extendSearchParam;
  }

這樣,將 dealOrderSourceCondition 的返回值改成 ExtendSearchParam 對象,就能使用 merge 方法來合併擴展搜索條件了。

Yeap ! 想想,除了 合併操做,還須要支持哪些操做呢 ?API 設計須要考慮周全,可不能遇到一個問題加一個支持啊 !

輔助方法

爲了與原來的 OrderSearchParam 聯合使用, 須要加一些輔助方法,好比:

public boolean has() {
    return CollectionUtils.isNotEmpty(extendConditions);
  }

  public List<EsCondition> getUnmodifiedExtendSearch() {
    return Collections.unmodifiableList(extendConditions);
  }


小結

本文講解了一個擴展搜索 API 的優化過程。好的 API 設計能提高業務方的使用體驗,下降維護成本。設計優雅的 API ,須要掌握一些技巧:工廠方法、重載方法、經常使用操做等。

從工做中不斷髮現須要優化的地方,掌握方法和技巧去解決, 也是一種提高技能的方式。

相關文章
相關標籤/搜索