插件系統(tǒng)概述
普通的系統(tǒng),在編譯發(fā)布之后,系統(tǒng)就不允許進(jìn)行更改或擴(kuò)充了,如果要進(jìn)行某個(gè)功能的擴(kuò)充,則必須要修改代碼重新編譯發(fā)布。使用插件可以很好地解決這個(gè)問(wèn)題。
插件概念
首先由開(kāi)發(fā)人員編寫(xiě)系統(tǒng)框架,并預(yù)先定義好系統(tǒng)的擴(kuò)展借口。插件由其他開(kāi)發(fā)人員根據(jù)系統(tǒng)預(yù)定的接口編寫(xiě)的擴(kuò)展功能,實(shí)際上就是系統(tǒng)的擴(kuò)展功能模塊。插件都是以一個(gè)獨(dú)立文件的形式出現(xiàn)。
對(duì)于系統(tǒng)來(lái)說(shuō)并不知道插件的具體功能,僅僅是為插件留下預(yù)定的接口,系統(tǒng)啟動(dòng)的時(shí)候根據(jù)插件的配置尋找插件,根據(jù)預(yù)定的接口把插件掛接到系統(tǒng)中。
優(yōu)勢(shì)
一、系統(tǒng)的擴(kuò)展性大大地加強(qiáng)了。如果我們?cè)谙到y(tǒng)發(fā)布后需要對(duì)系統(tǒng)進(jìn)行擴(kuò)充,就不必重新編譯,只需要增加或修改插件就可以了。
二、有利于模塊化的開(kāi)發(fā)方式。我們可以開(kāi)發(fā)強(qiáng)大的插件管理系統(tǒng),在這樣的一個(gè)插件系統(tǒng)下,我們可以不修改基本系統(tǒng),僅僅使用插件就能構(gòu)造出各種各樣不同的系統(tǒng)。
Eclipse系統(tǒng)架構(gòu)
Eclipse插件系統(tǒng)是非常成功的插件框架結(jié)構(gòu)。網(wǎng)上有很多介紹的文章。這里推薦孟巖的Blog http://www.mengyan.org/blog/archives/2005/09/08/67.html。下面對(duì)Eclipse的框架中的幾點(diǎn)做一個(gè)簡(jiǎn)要的介紹,在后面介紹插件系統(tǒng)架構(gòu)的時(shí)候作為對(duì)比。
插件結(jié)構(gòu)
Eclipse是眾多“可供插入的地方”(擴(kuò)展點(diǎn))和“可以插入的東西”(擴(kuò)展)共同組成的集合體。在我們的生活中,電源接線板就是一種“擴(kuò)展點(diǎn)”,很多“擴(kuò)展”(也就是電線插頭)可以插在它上面。(摘自《Contributing to Eclipse》 Erich Gamma, Kent Beck著)
Eclipse整個(gè)IDE就是一個(gè)插件,他提供了新的擴(kuò)展點(diǎn)供其他插件來(lái)擴(kuò)展。

擴(kuò)展點(diǎn)
可以看到Eclipse的插件結(jié)構(gòu)是由父插件管理子插件,插件之間由擴(kuò)展點(diǎn)連接,最終形成樹(shù)形的結(jié)構(gòu)。
界面呈現(xiàn)
界面呈現(xiàn)由提供擴(kuò)展點(diǎn)的父插件來(lái)決定,比如說(shuō)父插件在菜單上留了擴(kuò)展點(diǎn),那么子插件就可以出現(xiàn)在菜單項(xiàng)上。界面呈現(xiàn)的類(lèi)型是由提供擴(kuò)展的插件決定。
插件交互
插件之間的交互通過(guò)擴(kuò)展點(diǎn)實(shí)現(xiàn)。父插件調(diào)用子插件實(shí)現(xiàn)的擴(kuò)展點(diǎn)來(lái)觸發(fā)子插件的動(dòng)作。
依賴關(guān)系
配置文件中指定插件運(yùn)行需要依賴的插件,在裝載過(guò)程中會(huì)按照依賴的關(guān)系順序來(lái)裝載。
擴(kuò)展點(diǎn)形成的系統(tǒng)結(jié)構(gòu)
Eclipse中的插件用擴(kuò)展點(diǎn)的機(jī)制連接起來(lái),形成如下圖所示的系統(tǒng)結(jié)構(gòu)。插件必須實(shí)現(xiàn)擴(kuò)展點(diǎn),以此插入到系統(tǒng)中,新增擴(kuò)展點(diǎn)并不是必須的,但只有新增了擴(kuò)展點(diǎn)的插件才可以被別人擴(kuò)展。

懶加載
只有在調(diào)用執(zhí)行動(dòng)作的時(shí)候才會(huì)將真實(shí)的動(dòng)作對(duì)象創(chuàng)建起來(lái)。由于在配置文件中已經(jīng)具備真實(shí)動(dòng)作的一切信息,所以在不裝載插件時(shí),同樣可以在父插件的界面上將擴(kuò)展的功能顯示出來(lái)。
另一個(gè)插件系統(tǒng)
插件結(jié)構(gòu)
插件分為“插件外殼”和“業(yè)務(wù)”兩部分。
其中業(yè)務(wù)部分與插件沒(méi)有任何關(guān)系,按照一般的應(yīng)用程序開(kāi)發(fā)即可。最終提供給插件外殼一個(gè)主要的界面和公布出來(lái)的方法。
插件外殼提供接口供外界調(diào)用。系統(tǒng)和其它插件完全通過(guò)插件外殼和插件進(jìn)行交互。

界面呈現(xiàn)
將每個(gè)插件的界面按照一定形式組織起來(lái)生成整個(gè)系統(tǒng)。界面組織的規(guī)則在配置文件中指定。系統(tǒng)提供可配置的方案。
布局(Layout)
插件按照一定的布局放到整個(gè)系統(tǒng)的界面中。在目前的系統(tǒng)內(nèi)提供了三種布局。
頁(yè)面布局
將插件按照頁(yè)面的形式重疊在一起,插件激活時(shí)將自己所屬的頁(yè)面翻轉(zhuǎn)到最前端。

模塊布局
將插件按照模塊劃分放到同一個(gè)界面顯示。模塊之間用分割條連接。

頁(yè)簽布局
將插件按照頁(yè)簽的形式放到一起。

裝飾(Decorator)
布局指定了插件出現(xiàn)的位置與形式。裝飾可以指定插件出現(xiàn)的方式。
可關(guān)閉裝飾
指定插件出現(xiàn)的部分是否可以關(guān)閉。在普通的模式下,插件可以按照上面的幾種版型出現(xiàn),但這時(shí)的插件界面是不可關(guān)閉的。如果需要增加關(guān)閉功能,可以給插件指定一個(gè)裝飾器。
下面舉一個(gè)在模塊布局中的模塊2上應(yīng)用“可關(guān)閉裝飾”的例子。

布局、裝飾的組合
上面列舉了現(xiàn)有的布局與裝飾,復(fù)雜界面同樣可以有布局與裝飾的組合來(lái)完成。這里的圖式表明將三種布局與裝飾組合的一種情況。

通過(guò)配置文件指定出不同的組合情況就可以完成更多的界面布局了。在更改整個(gè)系統(tǒng)界面布局的時(shí)候只需要修改配置文件,程序并不需要重新發(fā)布。
導(dǎo)航
通過(guò)配置文件裝配好的插件系統(tǒng),界面可能是非常復(fù)雜的。這種情況下要讓用戶找到想要的功能需要用導(dǎo)航器來(lái)呈現(xiàn)系統(tǒng)提供的所用功能。
系統(tǒng)提供的功能就是插件提供的功能的集合,插件提供的功能通過(guò)插件外殼公布出來(lái)。公布的方式依照語(yǔ)言的特性來(lái)定:C#、Java中可以利用反射機(jī)制運(yùn)行公布出來(lái)的方法,Delphi中用RTTI也可以同樣運(yùn)行配置文件中指定的方法。
常見(jiàn)的導(dǎo)航器都可以抽象成樹(shù)形結(jié)構(gòu)。每一個(gè)導(dǎo)航單元映射到一個(gè)用戶需要的功能,每一個(gè)功能對(duì)應(yīng)到具體的插件的某一個(gè)方法。將功能抽象成一個(gè)Action對(duì)象,對(duì)象需要知道它導(dǎo)向的插件和方法名。

可以在上面抽象模型的基礎(chǔ)上實(shí)現(xiàn)任意形式的導(dǎo)航器。可以是菜單項(xiàng),可以是TreeView,也可以是自定義的控件。
交互關(guān)系
系統(tǒng)需要知道插件的操作,插件與插件之間同樣也會(huì)有交互。
將所有的交互關(guān)系用一個(gè)關(guān)系管理器來(lái)存儲(chǔ),插件與外界交互都通過(guò)關(guān)系管理器來(lái)實(shí)現(xiàn)。關(guān)系是在配置文件中指定,分析配置文件的時(shí)候就會(huì)將配置中指定的關(guān)系注冊(cè)到關(guān)系管理器中。
在運(yùn)行期,插件動(dòng)態(tài)從關(guān)系管理器中取得和自己關(guān)聯(lián)的接口。

懶加載
為了節(jié)省用戶資源,需要實(shí)現(xiàn)插件的按需加載,也叫懶加載,只有用到的插件才會(huì)從文件中裝載到內(nèi)存中運(yùn)行。
實(shí)現(xiàn)懶加載需要處理導(dǎo)航器和插件的布局。很多地方需要綁定插件的信息,但這時(shí)插件對(duì)象還不存在。使用代理插件可以解決這個(gè)問(wèn)題。

所有與插件的通信都通過(guò)代理插件對(duì)象來(lái)中轉(zhuǎn)。代理對(duì)象由主框架創(chuàng)建,記錄插件的基本信息。在系統(tǒng)裝載期,綁定到系統(tǒng)中的接口都是代理對(duì)象,當(dāng)外界需要與插件交互,例如顯示、運(yùn)行某個(gè)方法的時(shí)候,由代理來(lái)自動(dòng)裝載真實(shí)的插件,然后將調(diào)用委派給插件來(lái)響應(yīng)。這樣可以讓?xiě)屑虞d過(guò)程對(duì)于系統(tǒng)裝載,插件運(yùn)行是透明的。
架構(gòu)對(duì)比
微內(nèi)核 VS 巨內(nèi)核
Eclipse中的運(yùn)行框架非常小,系統(tǒng)中幾乎所有的都是插件,采用的是微內(nèi)核+插件的形式。在后面介紹的插件架構(gòu)中系統(tǒng)運(yùn)行框架比較復(fù)雜,它包括了界面布局策略、導(dǎo)航、插件代理等職責(zé),可以說(shuō)是巨內(nèi)核+插件的形式。
微內(nèi)核與巨內(nèi)核之爭(zhēng)已經(jīng)有很長(zhǎng)歷史了。在操作系統(tǒng)的概念中尤為突出。網(wǎng)上對(duì)于微內(nèi)核與巨內(nèi)核的討論同樣適用于插件系統(tǒng)。
僅從上面介紹的兩種插件系統(tǒng)來(lái)看,微內(nèi)核的好處在于系統(tǒng)的可擴(kuò)展性強(qiáng),如果你愿意,甚至可以將Eclipse整個(gè)開(kāi)發(fā)環(huán)境都替換掉;巨內(nèi)核的好處在于插件非常簡(jiǎn)單,只需要將業(yè)務(wù)部分用統(tǒng)一的接口公布出來(lái)就可以,在開(kāi)發(fā)具體模塊的時(shí)候可以不用考慮開(kāi)發(fā)的是否是插件。
界面呈現(xiàn)
微內(nèi)核中的界面呈現(xiàn)完全由父插件來(lái)決定,留了什么樣的擴(kuò)展點(diǎn)就可以在界面上以什么樣的形式發(fā)布功能。
巨內(nèi)核中的界面呈現(xiàn)由系統(tǒng)運(yùn)行框架決定,框架支持了幾種顯示的模式。配置文件可以在現(xiàn)有的模式之上隨意組合形成復(fù)雜的界面。在這個(gè)過(guò)程中插件并不關(guān)心自己被放在什么地方,或者以什么形式呈現(xiàn)。
插件關(guān)系
微內(nèi)核中的插件關(guān)系由插件自身來(lái)維持,插件實(shí)現(xiàn)的擴(kuò)展決定了它和父插件之間的交互關(guān)系,新增的擴(kuò)展點(diǎn)決定了它和將來(lái)在它基礎(chǔ)上擴(kuò)展的插件交互的模式。
巨內(nèi)核中的插件關(guān)系由系統(tǒng)框架(關(guān)系管理器)統(tǒng)一管理,插件本身不需要維護(hù)交互信息,只有在需要的時(shí)候才會(huì)從關(guān)系管理器取得。
懶加載
兩種架構(gòu)都可以支持插件的懶加載。基本的思路是一致的。但微內(nèi)核中的插件裝載由父插件來(lái)完成,而巨內(nèi)核中的裝載則直接由系統(tǒng)框架提供的統(tǒng)一代理類(lèi)來(lái)完成。
========================================================================================================
========================================================================================================
一切都是為了更加簡(jiǎn)單。
從函數(shù)到函數(shù)庫(kù),然后到類(lèi),然后到插件,都是因?yàn)槲覀兊能浖到y(tǒng)日益復(fù)雜,人腦畢竟有限,不能同時(shí)處理那么多的信息量,所以采用分而治之的方法來(lái)管理。
今年已經(jīng)研究了一年的插件系統(tǒng),從最開(kāi)始的懵懵懂懂到現(xiàn)在能有些經(jīng)驗(yàn)和大家分享,這個(gè)過(guò)程本身就是很有意思的。
最開(kāi)始系統(tǒng)中有了十幾個(gè)插件,經(jīng)過(guò)幾個(gè)月的慢慢發(fā)展,到了大幾十個(gè),甚至上百個(gè),這個(gè)數(shù)量就有些令人頭暈了。不過(guò)更加麻煩的還不是這近百個(gè)插件組裝而成的系統(tǒng),而是某一個(gè)插件系統(tǒng)需要調(diào)用另外的一個(gè)或多個(gè)插件系統(tǒng)。這樣的話,插件的數(shù)量就在100的基數(shù)上開(kāi)始翻倍。
如何做插件系統(tǒng)中的整合成了一個(gè)緊急的課題。
一、插件系統(tǒng)基本結(jié)構(gòu)
前面寫(xiě)過(guò)一篇文章,說(shuō)到了插件系統(tǒng)中的微內(nèi)核與巨內(nèi)核之分。不過(guò)不管是哪一種,任何一個(gè)系統(tǒng)都需要有一個(gè)啟動(dòng)點(diǎn),只不過(guò)對(duì)于插件系統(tǒng)中的啟動(dòng)步驟來(lái)說(shuō),它是一個(gè)通用,并且和具體業(yè)務(wù)無(wú)關(guān)的獨(dú)立模塊。
可以按照下面的圖示來(lái)簡(jiǎn)單理解插件系統(tǒng):

圖中的Launcher是插件系統(tǒng)的啟動(dòng)模塊,EntryPoint是系統(tǒng)的入口點(diǎn),作為一個(gè)接口給Launcher調(diào)用。啟動(dòng)模塊通過(guò)EntryPoint將系統(tǒng)運(yùn)行起來(lái)。系統(tǒng)中的插件相互協(xié)作滿足用戶的需要。
二、開(kāi)始集成
上面的圖將一個(gè)插件系統(tǒng)的基本原素描繪出來(lái)了。在具體的項(xiàng)目中,這樣的一個(gè)插件系統(tǒng)中插件的數(shù)量可能多達(dá)上百個(gè)。當(dāng)兩個(gè)項(xiàng)目組都在開(kāi)發(fā)各自的產(chǎn)品,項(xiàng)目組A需要將項(xiàng)目組B開(kāi)發(fā)的系統(tǒng)集成到自己的系統(tǒng)中時(shí),就要開(kāi)始考慮集成的問(wèn)題了。
系統(tǒng)中的插件之間存在父子關(guān)系,任何一個(gè)插件都可以作為另外一個(gè)插件的子插件存在。
如果將系統(tǒng)B作為系統(tǒng)A中某一個(gè)插件的子插件是不是就可以解決集成問(wèn)題了呢?——不錯(cuò),一個(gè)簡(jiǎn)單但實(shí)用的解決方法。
可以將插件系統(tǒng)考慮成一個(gè)函數(shù)庫(kù),函數(shù)庫(kù)中的幾百個(gè)函數(shù)相互協(xié)作完成一系列復(fù)雜的功能。現(xiàn)在我們需要在自己寫(xiě)的函數(shù)中包含上面函數(shù)庫(kù)中的所有功能怎么辦,簡(jiǎn)單的做法是將函數(shù)庫(kù)中的某個(gè)入口函數(shù)作為子函數(shù)調(diào)用就可以了。
下面介紹的集成方案基本上就是這個(gè)思路。
三、插件系統(tǒng)集成解決方案

3.1 EntryPoint與Endpoint
EntryPoint是插件系統(tǒng)的啟動(dòng)模塊調(diào)用系統(tǒng)功能的接口,這個(gè)接口是非常簡(jiǎn)單的,很多時(shí)候僅有一個(gè)Run方法,直接對(duì)應(yīng)到用戶的雙擊打開(kāi)程序的操作。
在系統(tǒng)A中要調(diào)用系統(tǒng)B時(shí),顯然一個(gè)簡(jiǎn)單的Run方法不能滿足要求,這里另外提出一個(gè)系統(tǒng)的入口點(diǎn)(端點(diǎn))Endpoint。
兩者的區(qū)別在于,EntryPoint對(duì)應(yīng)到Launcher的啟動(dòng)過(guò)程,參數(shù)簡(jiǎn)單;Endpiont對(duì)應(yīng)到其他系統(tǒng)的交互過(guò)程,參數(shù)復(fù)雜,需要通過(guò)Endpoint傳遞其他系統(tǒng)需要的信息。
3.2 BUS
有了每個(gè)系統(tǒng)的端點(diǎn),還需要將這些端點(diǎn)組合起來(lái),保證插件系統(tǒng)之間的相互通信。類(lèi)似于電腦中的總線概念。一旦每個(gè)系統(tǒng)的Endpoint掛接到了總線上,插件系統(tǒng)就可以通過(guò)總線查找到自己需要交互的其他插件系統(tǒng)了。
這里的總線用關(guān)系管理器來(lái)實(shí)現(xiàn)。因?yàn)?span lang="EN-US">Endpoint在插件系統(tǒng)中也是作為一個(gè)插件存在,這個(gè)插件的職責(zé)就是和外界交互。關(guān)系管理器可以處理任何插件之間的交互,盡管插件并不在同一個(gè)系統(tǒng)中。
3.3 Linker
在系統(tǒng)A中呈現(xiàn)系統(tǒng)B的功能有多種表現(xiàn)形式,比如說(shuō)在系統(tǒng)A的某個(gè)地方放上一個(gè)Button,點(diǎn)擊后系統(tǒng)B出現(xiàn);或者在系統(tǒng)A中放上一個(gè)頁(yè)簽,和一般功能并列將系統(tǒng)B呈現(xiàn)在系統(tǒng)A中。不管怎樣呈現(xiàn),可以將系統(tǒng)B看作系統(tǒng)A的一個(gè)插件。這個(gè)插件就是圖中的Linker。
Linker是系統(tǒng)B的一個(gè)代理插件,它本身并沒(méi)有實(shí)現(xiàn)業(yè)務(wù),只是將與系統(tǒng)B的交互以插件的形式呈現(xiàn)在系統(tǒng)A中。Linker通過(guò)總線找到對(duì)應(yīng)的插件系統(tǒng)并將它啟動(dòng),同時(shí)負(fù)責(zé)與它的交互。
四、適配器模式
Endpoint用的是Adapter的思想,將自身系統(tǒng)的功能以規(guī)定好的交互方式發(fā)布到總線上,這樣其他插件系統(tǒng)才能與之進(jìn)行交互。這種方法在系統(tǒng)的集成中用得非常多,已經(jīng)從設(shè)計(jì)模式上升到了架構(gòu)模式的層次。
有了這種適配器的方式,不僅僅是插件系統(tǒng)可以集成,甚至非插件系統(tǒng)同樣也可以集成到插件系統(tǒng)中來(lái)。所作的就是需要給非插件系統(tǒng)提供一個(gè)Adapter插件。對(duì)于其他插件系統(tǒng)來(lái)說(shuō),這個(gè)非插件系統(tǒng)在BUS的表現(xiàn)也和插件系統(tǒng)沒(méi)有差別了。

五、說(shuō)時(shí)容易做時(shí)難
上面提出了一種插件系統(tǒng)的集成方案,目前正在逐步的嘗試,過(guò)程中還遇到了一些細(xì)節(jié)上的問(wèn)題,今后等我慢慢整理出來(lái)再和大家分享。
現(xiàn)在只是做了插件系統(tǒng)與插件系統(tǒng)之間的集成,雖然從理論上說(shuō),插件系統(tǒng)與非插件系統(tǒng)的集成也同樣可行,不過(guò)目前還沒(méi)有實(shí)踐,不敢妄下定論。等有了機(jī)會(huì)再好好研究一下這方面的內(nèi)容。如果哪位朋友有一些好的經(jīng)驗(yàn)愿意分享,在下洗耳恭聽(tīng):)
========================================================================================================
========================================================================================================
插件可以封裝一定的業(yè)務(wù),同樣控件也具有封裝性。
可以說(shuō)控件的出現(xiàn)大大簡(jiǎn)化了我們開(kāi)發(fā)的工作量。作為一個(gè)插件系統(tǒng)來(lái)說(shuō),實(shí)現(xiàn)一個(gè)通用的插件能在更大粒度上進(jìn)行復(fù)用。插件是比控件更加高層的一種模塊封裝方式。
插件和控件有相同的地方:封裝和復(fù)用。本文分析了它們的異同,并且提出另外一個(gè)比較有趣的概念——偽插件。請(qǐng)大家繼續(xù)往下讀一讀。
一、插件和控件的比較
發(fā)布
控件編譯到系統(tǒng)中,和系統(tǒng)作為一個(gè)整體發(fā)布。
插件是在系統(tǒng)的運(yùn)行過(guò)程中動(dòng)態(tài)關(guān)聯(lián)到系統(tǒng)上,可以和系統(tǒng)的其他部分保持物理上的隔離。
配置能力
控件在系統(tǒng)中的呈現(xiàn)方式在編譯時(shí)已經(jīng)確定,通過(guò)代碼描述控件的表現(xiàn)形式,呈現(xiàn)位置等。
插件的呈現(xiàn)方式在運(yùn)行的時(shí)候根據(jù)外部的配置文件指定。
功用
控件作為公用的組件使用,在我們編寫(xiě)業(yè)務(wù)模塊時(shí),控件作為基本資源被我們使用。
插件作為一個(gè)獨(dú)立的業(yè)務(wù)模塊存在,直接面向用戶。
開(kāi)發(fā)調(diào)試
控件的調(diào)試簡(jiǎn)單,但插件的調(diào)試卻比較麻煩。正是因?yàn)闉榱遂`活性而制造的隔離措施導(dǎo)致了調(diào)試上的困難。通常一個(gè)插件作為一個(gè)工程開(kāi)發(fā)。
二、插件與控件的關(guān)系
插件是業(yè)務(wù)模塊,就像上面所說(shuō)的,在我們編寫(xiě)業(yè)務(wù)模塊時(shí)控件作為基本資源被使用。所以插件與控件的關(guān)系如下圖左所示,普通的業(yè)務(wù)模塊如下圖右所示。

可以看到,插件是滿足一定接口協(xié)議的業(yè)務(wù)模塊。
三、混亂的界限
作為控件使用的插件
如果一個(gè)插件中只有一個(gè)控件,并且沒(méi)有其他的業(yè)務(wù)邏輯。這種情況下它是插件還是控件?

就像上面所說(shuō)的,插件是帶有一定業(yè)務(wù)的模塊,并且是直接面向用戶作為一個(gè)系統(tǒng)功能來(lái)體現(xiàn)的。插件僅僅是封裝了一個(gè)控件,并沒(méi)有帶有其他的業(yè)務(wù)。像這種模塊是作為其他插件的子插件使用。如下圖所示。

這和我們上面看到的插件內(nèi)部直接包含控件就不一樣了。控件作為子插件的形式被其他插件使用。
插件的配置文件中會(huì)將自身的屬性作為配置,如標(biāo)題、圖標(biāo)、和其他一切可以作為配置的元素。但子插件沒(méi)有詳細(xì)的配置文件,它的屬性直接通過(guò)插件的接口暴露給父插件。
這類(lèi)的子插件是介于插件與控件之間的“偽插件”,因?yàn)樗⒉荒塥?dú)立地在系統(tǒng)中運(yùn)行,并且通常情況下不帶有業(yè)務(wù)邏輯,不能直接給用戶帶來(lái)價(jià)值。
發(fā)布后可更換控件
偽插件似乎沒(méi)有什么好處,誰(shuí)會(huì)無(wú)緣無(wú)故地在控件之上再封裝一層作為插件來(lái)使用?
可以想象一下,在系統(tǒng)發(fā)布后,我們需要改變某些插件中使用的控件。當(dāng)然,可以將那些插件全部重新編譯后發(fā)布。但如果使用這種“偽插件”的思路,我們可以開(kāi)發(fā)一個(gè)滿足同樣接口的另外一個(gè)偽插件,并在內(nèi)部使用不同的控件實(shí)現(xiàn)。這樣就可以在不發(fā)布其他插件的情況下,靈活地修改我們使用的控件了。
額外開(kāi)銷(xiāo)
如果所有的控件都像上面的來(lái)實(shí)現(xiàn),那簡(jiǎn)直是一場(chǎng)惡夢(mèng),并且也沒(méi)有這個(gè)必要。因?yàn)檫@樣做的成本比較大。
至于實(shí)際中是直接用控件,還是用偽插件的技術(shù),那就要看我們的決策了。