很想寫相關(guān)的內(nèi)容,一直以來(lái)這方面的東西很雜,自己各方面都多多少少有些總結(jié),但是沒有系統(tǒng)的成文,始終覺得是個(gè)遺憾。
這是這個(gè)系列的第一篇。
本文說(shuō)的架構(gòu),還并不是說(shuō)的Tier層的架構(gòu),這里面不會(huì)涉及到分布式、緩存、網(wǎng)絡(luò)結(jié)構(gòu)等等的布局,而是集中在軟件的內(nèi)部,是代碼層級(jí)的,考慮這點(diǎn)架構(gòu)的點(diǎn),目的是在于幫助我們寫出清晰、易維護(hù)的軟件。

關(guān)注點(diǎn)分離(Separation of concerns, SoC)

這個(gè)準(zhǔn)則應(yīng)該作為我們開發(fā)和架構(gòu)的指導(dǎo)性的原則。在該原則下,軟件應(yīng)該按照其業(yè)務(wù)來(lái)將軟件本身劃分成不同的部分,從而進(jìn)一步降低耦合性,不過(guò),這感覺是句廢話,大家好像都懂。

那么首先,關(guān)注點(diǎn)是什么呢?

比如說(shuō)一組對(duì)代碼有影響的業(yè)務(wù)邏輯,或?qū)δ硞€(gè)具體業(yè)務(wù)有影響的業(yè)務(wù)規(guī)則。它其實(shí)可以很通用,比如針對(duì)x86環(huán)境優(yōu)化代碼的細(xì)節(jié);也可以很具體,比如某個(gè)將要初始化的類的名字,只要它對(duì)我們是有用的,我們就稱它為其中的一個(gè)關(guān)注點(diǎn)。

舉例來(lái)說(shuō),如果某個(gè)軟件有個(gè)邏輯:是將某些產(chǎn)品高亮顯示出來(lái),以顯示這些產(chǎn)品的獨(dú)特性。
那么,把這些產(chǎn)品挑選出來(lái)的邏輯,應(yīng)該和把這些產(chǎn)品做高亮的邏輯分離開來(lái),這是兩個(gè)不同的關(guān)注點(diǎn)(只是剛好這兩個(gè)關(guān)注點(diǎn)是互相關(guān)聯(lián)的而已)。

在架構(gòu)上,如何去應(yīng)用這條準(zhǔn)則呢?比如說(shuō),把業(yè)務(wù)邏輯的行為分成基本的實(shí)現(xiàn)層(infrastruture)和UI層(理想的情況下,業(yè)務(wù)規(guī)則和業(yè)務(wù)邏輯都應(yīng)該分離到不同的項(xiàng)目里面去,他們也不能互相產(chǎn)生依賴的關(guān)系)。這種結(jié)構(gòu)能幫助我們保證業(yè)務(wù)邏輯更容易的測(cè)試和應(yīng)用,而且在底層也沒有互相耦合在一起。
關(guān)注點(diǎn)分離是我們對(duì)于軟件分層的一個(gè)核心的考慮點(diǎn)。

把握好這個(gè)尺度,有助于我們建造模塊化的應(yīng)用程序。它的價(jià)值在于簡(jiǎn)化開發(fā)和提高維護(hù)性。這個(gè)準(zhǔn)則做好了,各獨(dú)立部分就能重用,也可以相對(duì)獨(dú)立的開發(fā)和更新,某個(gè)模塊更新了,其他的模塊不必做額外的修改。

但是,聽起來(lái)還是好抽象的感覺。

舉例來(lái)說(shuō),ASP.NET MVC就是關(guān)注點(diǎn)分離的一個(gè)體現(xiàn),它將原來(lái)的ASP.NET WebForm分離成模型(model)-視圖(view)-控制器(controller),從而把業(yè)務(wù)邏輯、數(shù)據(jù)、界面分離,這也是組織代碼結(jié)構(gòu)的一個(gè)形式。

MVC的基本結(jié)構(gòu):

  • Model層表示應(yīng)用程序的數(shù)據(jù)核心,通常負(fù)責(zé)在數(shù)據(jù)庫(kù)中存取數(shù)據(jù)。

  • View是應(yīng)用程序的顯示層,通常是依據(jù)模型的數(shù)據(jù)而建立。

  • Controller是用來(lái)控制和處理輸入輸出的,是處理用戶交互的部分,也負(fù)責(zé)向模型(Model層)發(fā)送數(shù)據(jù)。

MVC的這個(gè)設(shè)計(jì)各個(gè)關(guān)注點(diǎn)是分開的,這樣有助于我們管理和開發(fā)復(fù)雜的應(yīng)用程序,我們可以在某個(gè)時(shí)間點(diǎn)只集中精力在其中的某一個(gè)關(guān)注點(diǎn),而不是所有的部分。舉例來(lái)說(shuō),前端的開發(fā)人員可以配合設(shè)計(jì)團(tuán)隊(duì)繞過(guò)業(yè)務(wù)邏輯,專注在視圖和交互設(shè)計(jì)部分。另外的一端,DBA也可以配合某個(gè)團(tuán)隊(duì)專注在數(shù)據(jù)持久化的部分,而中間的業(yè)務(wù)邏輯層又可以由其他團(tuán)隊(duì)集中精力來(lái)負(fù)責(zé)。這種分層也簡(jiǎn)化了分組開發(fā),讓測(cè)試也更為容易。

除了ASP.NET MVC還有其他的框架也是這樣的關(guān)注點(diǎn)分離的思想,比如Django,Structs,Spring等等。

那么分層思想都有哪些方法呢,總不至于只是用個(gè)MVC就結(jié)束了吧?

其實(shí)東西還是比較多的,下面,將介紹一些分層的思想。

縱向分離

大家都懂,即便是最初級(jí)的程序員也都接觸過(guò),可能是你并沒有意識(shí)到而已。
我們十好幾年前的三層架構(gòu),界面層(UI Layer),業(yè)務(wù)邏輯層(Business Layer)和數(shù)據(jù)持久化層(Data Access Layer),就是這一種自上而下的縱向的分層手法。

橫向分離

大家也懂。我們倡導(dǎo)的模塊化的編程,把我們的軟件拆分成模塊或子系統(tǒng)。
從左到右是模塊1、模塊2、模塊3,這是一種水平方向的切割。
這跟縱向的分離是兩個(gè)不同的方向,橫向分離大多是模塊化的過(guò)程。

切面分離

有些內(nèi)容是多個(gè)層之間都需要的,比如日志(logging),在你的系統(tǒng)里面,界面層、邏輯層、數(shù)據(jù)訪問層可能都需要寫日志,這種跨到多層同樣邏輯就可以考慮切面分離。
在asp.net mvc中,我們可以使用filter來(lái)實(shí)現(xiàn), Spring中也有SpringAOP等等。

依賴方向分離

我們考慮這幾點(diǎn):

  • 有些類要修改的幾率比其他的類修改的幾率大得多。

  • 具體的類比抽象類修改的幾率大得多。

  • 修改被依賴得很多的類可能引起很大的改動(dòng)。

  • 某些類比其他類被重用的可能性大得多。

依據(jù)這些考慮點(diǎn),我們來(lái)決定某個(gè)類應(yīng)該放在哪個(gè)層次里面,或者考慮將某一層切割成多層。

關(guān)注數(shù)據(jù)分離

在組織數(shù)據(jù)時(shí),應(yīng)該盡量考慮數(shù)據(jù)本身的固有屬性,如果不是它們的固有屬性,那么應(yīng)該分離出來(lái)。

比如產(chǎn)品的類就不應(yīng)該關(guān)聯(lián)customer類,因?yàn)楫a(chǎn)品不應(yīng)該跟客戶直接產(chǎn)生數(shù)據(jù)關(guān)系,產(chǎn)品的顏色、型號(hào)、描述才是產(chǎn)品該有的固有屬性。

至于客戶,應(yīng)該是用訂單類來(lái)把他們聯(lián)系在一起。

關(guān)注行為分離

跟上面講的一樣,行為也應(yīng)該是事物或?qū)ο蟮墓逃械谋旧淼男袨?,明顯偏離原來(lái)行為的,應(yīng)該考慮成另外的關(guān)注點(diǎn)兒分離開。

比如有一個(gè)函數(shù)叫做CreateNewCustomer(),那么CreateNewCustomer的行為就應(yīng)該限定在創(chuàng)建一個(gè)新客戶上面,給新客戶自動(dòng)發(fā)優(yōu)惠券的動(dòng)作就不能放到這個(gè)函數(shù)里面。

擴(kuò)展分離

如果基于某種設(shè)計(jì),原先不具有某些行為需要增加,可以考慮通過(guò)擴(kuò)展或插件的形式來(lái)完成,將這些功能放入到插件或擴(kuò)展中,就是擴(kuò)展分離。

比如Firefox、Chrome的去廣告的插件,這些功能增加了系統(tǒng)原本的行為,將這些行為分離到插件里面去,就是擴(kuò)展分離。

委托分離

如果某個(gè)行為還無(wú)法具體確定,可以使用委托的方式。
比如C#的delegate,當(dāng)我們還不知道某些具體行為應(yīng)該如何實(shí)現(xiàn),或者不應(yīng)該在此處對(duì)該行為進(jìn)行實(shí)現(xiàn),或者有多個(gè)行為可以互相替代,就可以將函數(shù)的參數(shù)指定為一個(gè)delegate。

至于delegate具體怎樣實(shí)現(xiàn),那是其他部分應(yīng)該關(guān)注的點(diǎn)。

比如現(xiàn)在需要將Customer的信息持久化,就可以把這個(gè)請(qǐng)求委托給DatabaseManager或WebSerivceManager,由他們自行處理數(shù)據(jù),然后返回給我結(jié)果。

反轉(zhuǎn)分離

現(xiàn)在有了很多的依賴注入的框架,像Autofac,Unit,Castle Windsor等等,這些幫助我們做依賴翻轉(zhuǎn),從而倒置依賴關(guān)系。

要指出是,上面提到了9種分離層次的概念,每一種概念都可以任意的與其他概念組合在一起,從而產(chǎn)生更多的變化。

在實(shí)際的開發(fā)過(guò)程中,沒有東西是一成不變的,而層次和架構(gòu)也應(yīng)該是在開發(fā)的過(guò)程里面不斷完善和重構(gòu)。

初級(jí)程序員最煩的是需求或業(yè)務(wù)的修改,一些我們覺得奇奇怪怪的修改導(dǎo)致大家不斷的修改代碼,心里很煩,在心里也默默的把產(chǎn)品經(jīng)理被翻過(guò)來(lái)倒過(guò)去罵了千百遍。

但是,在實(shí)際的工作中你會(huì)發(fā)現(xiàn),軟件開發(fā)就是這樣,沒有什么是不變的。

如果一定要找出一個(gè)不變的點(diǎn),我想那應(yīng)該是:

唯一不變的,就是變化。

關(guān)于不斷的修改與重構(gòu),也可以參考《重構(gòu)-改善既有代碼的設(shè)計(jì)》,記得封面上寫的是:

軟件開發(fā)的不朽經(jīng)典
生動(dòng)闡述重構(gòu)原理和具體做法
普通程序員進(jìn)階到編程高手必須修煉的秘笈

呃,再往下面離題越來(lái)越遠(yuǎn)了。
至此,關(guān)注點(diǎn)分離這塊內(nèi)容暫告一段落。

http://www.cnblogs.com/asis/p/architecture-Soc.html