聊聊高煥堂老師的EIT架構(gòu)

今年春節(jié)的時(shí)候,我在51CTO上選中了新的課程,就是高煥堂老師的EIT架構(gòu)。由于自己對(duì)架構(gòu)比較感興趣,剛好又有這種題材的講座,因此很愉快的學(xué)習(xí)了一下,感覺(jué)也有很多收獲,在這里簡(jiǎn)單的記錄一下

什么是EIT

實(shí)際上這個(gè)名詞我也是偶然間得知的,就是自己在聽(tīng)高老師講的jni系列課程的時(shí)候,反復(fù)的提到了EIT,當(dāng)時(shí)一臉迷茫,什么是EIT呢?于是百度了一下。發(fā)現(xiàn)似乎并沒(méi)有相關(guān)的介紹。在高老師的個(gè)人主頁(yè)上找了半天也沒(méi)有找到。剛好發(fā)現(xiàn)高老師講的架構(gòu)相關(guān)的課程,就是介紹EIT的講座,好奇的就學(xué)起來(lái)了。

老實(shí)說(shuō)剛開(kāi)始聽(tīng)前幾集講座的時(shí)候,還是不太明白高老師要表達(dá)的意思。雖然老是提到EIT,EIT,但從始至終也沒(méi)有說(shuō)明什么是E,什么是I,什么是T。我也是看到了講座中的一張圖后,才大概明白了EIT的含義,也就是下面的圖:

image.png

也就是說(shuō)E&&I是在一個(gè)類中的,T是其子類,這是一個(gè)基本的形式
另一種擴(kuò)展的形式是這樣的

image.png

和上面的圖稍微有些不同,接口層interface被抽象出來(lái)了
這個(gè)圖已經(jīng)給出了EIT的英文名稱,即engine,interface和tire,但是這三者是什么關(guān)系呢?engine是引擎的意思,interface是接口,而tire是輪胎。一開(kāi)始我沒(méi)有明白高老師的含義,尤其是EIT的基本型而言,T是子類,怎么能說(shuō)輪胎是引擎的子類呢?隨著學(xué)習(xí)的逐漸深入,我終于明白,原來(lái)這里的EIT是按照擴(kuò)展型中的圖定義的,也就是一個(gè)汽車引擎,需要有四個(gè)輪胎構(gòu)成,這里引擎并不直接依賴于具體的輪胎,而是依賴于接口interface,而tire實(shí)現(xiàn)了這個(gè)接口,于是在編碼中就很有彈性了,即,我需要什么輪胎我就組裝什么輪胎就可以了,甚至在運(yùn)行的時(shí)候,我還可以換輪胎。這樣的設(shè)計(jì),顯然代碼會(huì)更有彈性。

設(shè)計(jì)模式

上面的兩種形式,大概是高老師在設(shè)計(jì)模式的基礎(chǔ)上,高度抽象而來(lái)。實(shí)際上上面的兩個(gè)圖,正是代表了設(shè)計(jì)模式中的兩種經(jīng)典的模型。

首先我想介紹一下設(shè)計(jì)模式中的精髓,也就是接口。為什么說(shuō)接口很重要呢?因?yàn)榻涌诳梢宰寖蓚€(gè)銜接的模塊解耦,讓雙方互相不知道對(duì)方的存在,這在編碼架構(gòu)中,具有非常好的彈性。

設(shè)計(jì)模式有很多種,但最核心的就是五大原則了。在這五大原則中,我覺(jué)得最重要的,就是最后一個(gè)原則,就是開(kāi)閉原則,即對(duì)擴(kuò)展是開(kāi)放的,對(duì)修改是封閉的。也就是說(shuō),如何判斷我們寫的架構(gòu)好不好呢?其實(shí)很簡(jiǎn)單,如果追加一個(gè)類似的功能,可不可以?這就是擴(kuò)展型。在擴(kuò)展的同時(shí)是否必須需要破壞之前的代碼?還是直接追加新的文件就可以了,以前的文件可以最大程度的保持不變?這就是封閉性。如果你寫的架構(gòu),同時(shí)具備擴(kuò)展型和封閉性,那么就真的是一個(gè)好的架構(gòu)了。

舉個(gè)例子,如果需要實(shí)現(xiàn)一個(gè)架構(gòu),小明每天騎車上班,我們應(yīng)該如何設(shè)計(jì)呢?
我想最直觀的設(shè)計(jì)就是下圖了

image.png

這實(shí)在是太簡(jiǎn)單了,剛學(xué)會(huì)編程的人,大概也可以寫的出來(lái)這個(gè)代碼。
我們簡(jiǎn)單的寫一下這個(gè)代碼評(píng)估一下

class Person {
    void take(Bike* bike);
};

class Bike {

};

int main(int argc, char* argv) {
    Person* person = new Person();
    Bike* bike = new Bike();
    person->take(bike);
    return 0;
}

這真的不是很難。
該如何評(píng)估這個(gè)架子是否好呢?就用上面的兩個(gè)法則,其一,檢驗(yàn)是否有擴(kuò)展性,比如現(xiàn)在提出一個(gè)新需求,小明坐公交上班,這個(gè)架構(gòu)是否也同樣適用?當(dāng)然了可以適用,只需要添加一個(gè)Bus類,并且將Person類中take的參數(shù),改為Bus* bus就可以了。其二,檢驗(yàn)是否是封閉的,我們?yōu)榱藬U(kuò)展新的需求,不得不修改已經(jīng)寫好的類中的代碼,即改變了Person中方法的參數(shù),這顯然不滿足封閉性。
特別的,如果我需要增加更多的交通工具,Person類就要不斷的修改,顯然,這個(gè)架構(gòu)設(shè)計(jì),smell bad。

為什么這兩個(gè)特性都至關(guān)重要呢?擴(kuò)展性就不必多說(shuō)了,如果一個(gè)系統(tǒng)一點(diǎn)點(diǎn)擴(kuò)展性都沒(méi)有,顯然不會(huì)是一個(gè)很好的系統(tǒng)。為什么我們需要保持封閉性呢?因?yàn)槲覀儾环忾]就意味著之前的代碼需要修改,那之前的一些工作無(wú)疑就白做了。比如Person類測(cè)試已經(jīng)充分驗(yàn)證,完全沒(méi)有問(wèn)題,可以給用戶使用,但是為了擴(kuò)展一個(gè)新的功能,我們不得不修改Person類,這樣之前的測(cè)試結(jié)果又要重來(lái)一遍,誰(shuí)知道你引入的新的代碼,會(huì)不會(huì)引起新的bug呢~

進(jìn)一步思考,為何我們的設(shè)計(jì)會(huì)破壞了開(kāi)閉原則呢?就是因?yàn)槲覀冏尵唧w的東西Person,依賴于了具體的東西Bike了。也就是兩個(gè)具體的東西耦合在了一起,因此Bike的改變必然會(huì)引起Person的改變。正確的做法,應(yīng)該是依賴于抽象!因此我們要從交通工具中找到共通點(diǎn),從而抽象出抽象的接口

image.png

好了,這樣一來(lái),Person這個(gè)具體的東西,依賴于Traffic這個(gè)接口,那么Bike的改變就不會(huì)引起Person的改變了
簡(jiǎn)單的代碼如下

class Traffic;

class Person {
    void take(Traffic* trafic);
};

class Traffic {

};

class Bike : public Traffic {

};

class Bus : public Traffic {

};

int main(int argc, char* argv[]) {
    Person* person = new Person();
    Traffic* traffic = new Bike();
    person->take(traffic);
}

這樣的設(shè)計(jì),顯然比剛才的設(shè)計(jì)就改良了不少,如果你還想擴(kuò)展新的交通工具,只要做相應(yīng)的子類就可以了,這個(gè)擴(kuò)展,也不會(huì)引起Person類的修改,完全符合設(shè)計(jì)模式的原則,真的很不錯(cuò)。

說(shuō)到這里,我們其實(shí)就描述了一個(gè)設(shè)計(jì)模式:策略模式。什么是策略模式呢?我們?nèi)ド习鄬?shí)際上是一種策略,也就是這里的traffic接口,而具體的策略,比如是騎自行車,還是做公交車之類的由子類決定。

EIT與設(shè)計(jì)模式

介紹完設(shè)計(jì)模式,特別是策略模式,我們可以在EIT中找到策略模式的影子。E可以看做是Person,I可以看做是Traffic接口,而B(niǎo)ike以及Bus,就是具體的T。所以擴(kuò)展的EIT模式,就可以看做是設(shè)計(jì)模式中的策略模式。

對(duì)于標(biāo)準(zhǔn)的EIT模型,設(shè)計(jì)模式中也有與其相對(duì)應(yīng)的一種,即模板模式。模板模式的應(yīng)用場(chǎng)景是這樣的,做一件事,可能分為幾個(gè)步驟,但是在做具體的步驟的時(shí)候,不同的用戶做法不同,我們將這些具體的步驟做成接口,讓用戶在實(shí)現(xiàn)子類中實(shí)現(xiàn)。比如,我們?cè)谂判虻臅r(shí)候需要知道如何判斷兩個(gè)數(shù)的大小,這個(gè)具體的算法,由用戶決定,因此做成接口。用戶在準(zhǔn)備排序時(shí),只需要提供如何判斷兩個(gè)數(shù)大小的方法就可以,至于如何排好序,基類就已經(jīng)實(shí)現(xiàn)好了,用戶不需要知道。

因此從這里看來(lái),EIT的基本形式和擴(kuò)展形式,實(shí)際上就對(duì)應(yīng)了設(shè)計(jì)模式中的兩種經(jīng)典的模式模板模式以及策略模式。讓我們繼續(xù)挖掘一下這兩個(gè)形式?;拘问绞荅&&I做在了一起,即在一個(gè)類中,而T繼承了I,這就是一個(gè)典型的繼承關(guān)系,也就是is-a的關(guān)系。而擴(kuò)展形式是E有一個(gè)接口I,T實(shí)現(xiàn)了接口I,這就是一個(gè)has-a的關(guān)系。這兩種關(guān)系各有利弊。設(shè)計(jì)模式中的建議,是讓我們盡量多用組合的方式,即has-a的關(guān)系,而少用繼承的關(guān)系,即用組合來(lái)替代繼承。這樣做的好處時(shí),組合關(guān)系在運(yùn)行時(shí)是可以替換的。比如小明騎車上班,在中間突然想換公交車了,這也是完全可以的。

內(nèi)容與形式

我們說(shuō)EIT有兩種形式,基本形式和擴(kuò)展形式,什么是形式呢?形式就是一種套路。高老師的意思是我們需要編碼的任何內(nèi)容都可以放在這個(gè)形式中。你看,這里就提到了內(nèi)容和形式。我們需要編碼的,就是內(nèi)容,EIT就是形式,也就是,我們需要編碼的任何東西,都可以以EIT的形式呈現(xiàn)。

比如剛才提到的小明騎車上班,就是內(nèi)容,我們剛才用策略模式實(shí)現(xiàn),即EIT的擴(kuò)展型實(shí)現(xiàn),就是一種形式。也就是我們用EIT的形式,實(shí)現(xiàn)了小明騎車上班的內(nèi)容。

那么,真的所有復(fù)雜的代碼架構(gòu),都可以通過(guò)EIT的形式展示嗎?實(shí)際上是可以的,但絕不僅僅是一種形式,復(fù)雜代碼架構(gòu),是由EIT這種簡(jiǎn)單的形式組合而成。

事實(shí)上,這里蘊(yùn)含的思想非常重要:任何復(fù)雜的東西都是由簡(jiǎn)單的東西堆砌而成。所以在拿到一個(gè)復(fù)雜的架構(gòu)的時(shí)候,我們需要將他首先拆解成幾個(gè)簡(jiǎn)單東西的組合,有的時(shí)候簡(jiǎn)單的東西還需要繼續(xù)拆解。而拆解到最后的功能或者功能組,也就是內(nèi)容,都可以通過(guò)EIT這種形式展示出來(lái),最后,我們將這些EIT的形式組合到一起,ok,復(fù)雜的架構(gòu)就開(kāi)發(fā)出來(lái)了。

我覺(jué)得這種思想也體現(xiàn)了軟件架構(gòu)設(shè)計(jì)的重要思路。
因此拿到一個(gè)需求,我們首先需要將需求分解,再提取出接口,分的好,接口設(shè)計(jì)的好,架構(gòu)就越好。

強(qiáng)龍不壓地頭蛇

高老師進(jìn)一步提出了強(qiáng)龍不壓地頭蛇的思想。什么是強(qiáng)龍?強(qiáng)龍做的就是E&&I,什么是地頭蛇?地頭蛇做的就是T
說(shuō)的直觀一點(diǎn),強(qiáng)龍就是做框架設(shè)計(jì)的,而地頭蛇,就是做定制化開(kāi)發(fā)的。

比如Android,谷歌的程序員們,就是強(qiáng)龍,他們負(fù)責(zé)做框架的開(kāi)發(fā),他們將功能與任務(wù)進(jìn)行分解,并且流出了必要的接口I,比如Activity中流出了接口OnCreate,OnDestroy等等。而我們這些程序開(kāi)發(fā)者,就是要實(shí)現(xiàn)強(qiáng)龍們?yōu)槲覀冊(cè)O(shè)計(jì)好的接口,做定制化的開(kāi)發(fā)。這樣,就產(chǎn)生了形形色色的不同的Android應(yīng)用。

因此架構(gòu)師們的核心工作就是,將系統(tǒng)進(jìn)行拆解,設(shè)計(jì)出接口I,接口的設(shè)計(jì),體現(xiàn)了一個(gè)架構(gòu)師的能力,接口設(shè)計(jì)的好,地頭蛇們開(kāi)發(fā)的就會(huì)非常開(kāi)心。

尾聲

好了,對(duì)于高老師的這套架構(gòu)講座,就暫時(shí)總結(jié)到這里了。
我覺(jué)得自己的收獲還是很大的。高老師提出的EIT的思路確實(shí)很有借鑒意義。

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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