插件化框架下模塊間接口新嘗試(一種反設(shè)計(jì)模式的接口設(shè)計(jì))

插件化是一種利用分治思想對(duì)項(xiàng)目進(jìn)行降維開(kāi)發(fā)的思路。當(dāng)然組件化也能起到降維和分治的目的,但是組件化這個(gè)詞已經(jīng)是教科書(shū)上都有提及的概念了,大多數(shù)應(yīng)用開(kāi)發(fā)中遇到的問(wèn)題都是基于插件化的,因?yàn)椴寮瘜?duì)比組件化增加了熱插拔的功能,也就是說(shuō)使用插件化框架能夠?qū)崿F(xiàn)應(yīng)用的動(dòng)態(tài)更新。

近期某互聯(lián)網(wǎng)公司發(fā)布消息說(shuō)要開(kāi)源自己的插件框架源碼。雖然插件化的概念在安卓開(kāi)發(fā)領(lǐng)域已經(jīng)火了有些日子了,但始終沒(méi)有發(fā)現(xiàn)一款大家都滿意的、普適的插件框架。目前已知在研究插件框架的公司已經(jīng)超過(guò)了5個(gè),所以對(duì)要開(kāi)源的這款也不置可否,但不管使用哪種類型的插件框架,抑或只是使用組件化對(duì)項(xiàng)目進(jìn)行切分,都會(huì)遇到題目中所描述的問(wèn)題模塊間接口設(shè)計(jì)。

既然要按插件化或組件化把項(xiàng)目分成多個(gè)模塊,那么無(wú)可避免地需要多個(gè)模塊之間進(jìn)行數(shù)據(jù)或邏輯交互。按照設(shè)計(jì)模式中的開(kāi)閉原則,大家第一想法多半是暴露服務(wù)接口、封閉服務(wù)實(shí)現(xiàn)。于是給服務(wù)新加了以下接口:

public interface Service {
  int method();
}

為了在各個(gè)插件中方便地注冊(cè)或獲取服務(wù),在插件框架中需要一個(gè)統(tǒng)一管理服務(wù)的機(jī)制,類似于:

public class PluginFramework {
  public static void registerService(String key, Object service) {
    /* todo */
  }

  public static void unregisterService(String key) {
    /* todo */
  }

  public static Object getService(String key) {
    return null;
    /* todo */
  }
}

當(dāng)在某個(gè)插件里需要調(diào)用該服務(wù)時(shí),首先你需要從插件框架提供的統(tǒng)一服務(wù)管理機(jī)制中獲取該服務(wù),然后才能調(diào)用該服務(wù)提供的方法(注意此時(shí)需要對(duì)獲取的服務(wù)進(jìn)行判空保護(hù)),類似于:

public class Test {
  public void function() {
    Service service = (Service) PluginFramework.getService("key");
    if (service != null) {
      service.method();
    }
  }
}

以上,一個(gè)標(biāo)準(zhǔn)的符合設(shè)計(jì)模式思想的模塊間接口就設(shè)計(jì)好了。

轉(zhuǎn)

既然項(xiàng)目分成了多個(gè)模塊,我們就希望各個(gè)模塊之間共有的邏輯盡可能少,但實(shí)際開(kāi)發(fā)中往往會(huì)遇到一些通用性很強(qiáng)、出現(xiàn)頻率很高又非常重要的邏輯穿插整個(gè)項(xiàng)目,我們既不能刪掉它,又找不到很好的方法把這塊邏輯封裝到一個(gè)單獨(dú)的模塊里,但是它出現(xiàn)的頻率很高,而且每出現(xiàn)一次都需要三步操作(1.獲取/2.判空/3.調(diào)用)。極端情況下,一個(gè)n行可以實(shí)現(xiàn)的邏輯,我們就需要3*n的代碼量去實(shí)現(xiàn),這在快速迭代的需求開(kāi)發(fā)中是很影響程序猿的編碼速度的,同時(shí)業(yè)務(wù)代碼的可讀性可見(jiàn)一斑?;谝陨峡紤],我在項(xiàng)目中對(duì)模塊間的接口進(jìn)行了以下嘗試:

public class Service {
  private static Service service;

  private static Service getService() {
    if (service == null) {
      service = new Service();
    }
    return service;
  }

  protected int methodImpl() {
    return 0;
  }

  public static int method() {
    return getService().methodImpl();
  }
}

將抽象的接口和接口的默認(rèn)實(shí)現(xiàn)完全耦合在一起,這樣即使提供服務(wù)的一方?jīng)]有及時(shí)注冊(cè)服務(wù),使用服務(wù)的一方也可以隨時(shí)調(diào)用服務(wù)的方法,完全不必考慮空指針問(wèn)題,因?yàn)槲覀冇幸粋€(gè)默認(rèn)的實(shí)現(xiàn)。此時(shí)該服務(wù)的注冊(cè)和反注冊(cè)是在服務(wù)類內(nèi)部實(shí)現(xiàn)的,也就不需要跟PluginFramework有任何牽連了。

public class Service {
  private static Service service;

  protected final void register() {
    service = this;
  }

  protected final void unregister() {
    service = null;
  }
}

注意register和unregister方法是protected final的,如果要進(jìn)行注冊(cè)和反注冊(cè)操作的話,業(yè)務(wù)方必須實(shí)現(xiàn)一個(gè)子類集成Service,然后在子類內(nèi)部調(diào)用register方法,這在一定程度上可以避免業(yè)務(wù)方誤操作導(dǎo)致已注冊(cè)服務(wù)被覆蓋的問(wèn)題。

此時(shí)業(yè)務(wù)方調(diào)用服務(wù)提供的方法時(shí),代碼就成了這個(gè)樣子:

public class Test {
  public void function() {
    Service.method();
  }
}

細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),這種接口設(shè)計(jì)方式并不符合開(kāi)放接口、封閉實(shí)現(xiàn)的原則,還將接口、默認(rèn)實(shí)現(xiàn)、服務(wù)管理邏輯完全耦合在了一起,這就是我之所以把它稱之為反設(shè)計(jì)模式的原因。

教科書(shū)上說(shuō):設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性,然后才有了6原則、23模式。在實(shí)際的結(jié)構(gòu)設(shè)計(jì)中,記性好的同學(xué)可能會(huì)首選23種模式為參考,稍微懶點(diǎn)兒的同學(xué)大概就只記得6原則了,像我這種7秒就什么都不記得的,只好什么都不管了。某偉人曾經(jīng)說(shuō)過(guò),不管黑貓白貓抓到老鼠就是好貓,所以私以為只要設(shè)計(jì)出來(lái)的代碼好使好用好看,就不要考慮什么原則什么模式了吧。

如果要強(qiáng)行站隊(duì)的話,本文提到的這種反設(shè)計(jì)模式的接口設(shè)計(jì)思路跟迪米特法則能靠上邊兒吧,不管怎么說(shuō)業(yè)務(wù)方調(diào)用的時(shí)候方便了,不管你有沒(méi)有實(shí)現(xiàn)有沒(méi)有注冊(cè)都可以直接調(diào)用服務(wù)的方法,提供服務(wù)的系統(tǒng)模塊的確更加獨(dú)立了呢~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容