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%")));
啊啊,真是醜死了 ! 爲何呢 ?設計
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 ,須要掌握一些技巧:工廠方法、重載方法、經常使用操做等。
從工做中不斷髮現須要優化的地方,掌握方法和技巧去解決, 也是一種提高技能的方式。