架構漫談系列(1) 關注點分離


很想寫相關的內容,一直以來這方面的東西很雜,自己各方面都多多少少有些總結,但是沒有系統的成文,始終覺得是個遺憾。
這是這個系列的第一篇。
本文說的架構,還並不是說的Tier層的架構,這里面不會涉及到分布式、緩存、網絡結構等等的布局,而是集中在軟件的內部,是代碼層級的,考慮這點架構的點,目的是在於幫助我們寫出清晰、易維護的軟件。

關注點分離(Separation of concerns, SoC)

這個准則應該作為我們開發和架構的指導性的原則。在該原則下,軟件應該按照其業務來將軟件本身划分成不同的部分,從而進一步降低耦合性,不過,這感覺是句廢話,大家好像都懂。

那么首先,關注點是什么呢?

比如說一組對代碼有影響的業務邏輯,或對某個具體業務有影響的業務規則。它其實可以很通用,比如針對x86環境優化代碼的細節;也可以很具體,比如某個將要初始化的類的名字,只要它對我們是有用的,我們就稱它為其中的一個關注點。

舉例來說,如果某個軟件有個邏輯:是將某些產品高亮顯示出來,以顯示這些產品的獨特性。
那么,把這些產品挑選出來的邏輯,應該和把這些產品做高亮的邏輯分離開來,這是兩個不同的關注點(只是剛好這兩個關注點是互相關聯的而已)。

在架構上,如何去應用這條准則呢?比如說,把業務邏輯的行為分成基本的實現層(infrastruture)和UI層(理想的情況下,業務規則和業務邏輯都應該分離到不同的項目里面去,他們也不能互相產生依賴的關系)。這種結構能幫助我們保證業務邏輯更容易的測試和應用,而且在底層也沒有互相耦合在一起。
關注點分離是我們對於軟件分層的一個核心的考慮點。

把握好這個尺度,有助於我們建造模塊化的應用程序。它的價值在於簡化開發和提高維護性。這個准則做好了,各獨立部分就能重用,也可以相對獨立的開發和更新,某個模塊更新了,其他的模塊不必做額外的修改。

但是,聽起來還是好抽象的感覺。

舉例來說,ASP.NET MVC就是關注點分離的一個體現,它將原來的ASP.NET WebForm分離成模型(model)-視圖(view)-控制器(controller),從而把業務邏輯、數據、界面分離,這也是組織代碼結構的一個形式。

MVC的基本結構:

  • Model層表示應用程序的數據核心,通常負責在數據庫中存取數據。

  • View是應用程序的顯示層,通常是依據模型的數據而建立。

  • Controller是用來控制和處理輸入輸出的,是處理用戶交互的部分,也負責向模型(Model層)發送數據。

    MVC的這個設計各個關注點是分開的,這樣有助於我們管理和開發復雜的應用程序,我們可以在某個時間點只集中精力在其中的某一個關注點,而不是所有的部分。舉例來說,前端的開發人員可以配合設計團隊繞過業務邏輯,專注在視圖和交互設計部分。另外的一端,DBA也可以配合某個團隊專注在數據持久化的部分,而中間的業務邏輯層又可以由其他團隊集中精力來負責。這種分層也簡化了分組開發,讓測試也更為容易。

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

那么分層思想都有哪些方法呢,總不至於只是用個MVC就結束了吧?

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

縱向分離

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

橫向分離

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

切面分離

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

依賴方向分離

我們考慮這幾點:

  • 有些類要修改的幾率比其他的類修改的幾率大得多。
  • 具體的類比抽象類修改的幾率大得多。
  • 修改被依賴得很多的類可能引起很大的改動。
  • 某些類比其他類被重用的可能性大得多。

依據這些考慮點,我們來決定某個類應該放在哪個層次里面,或者考慮將某一層切割成多層。

關注數據分離

在組織數據時,應該盡量考慮數據本身的固有屬性,如果不是它們的固有屬性,那么應該分離出來。

比如產品的類就不應該關聯customer類,因為產品不應該跟客戶直接產生數據關系,產品的顏色、型號、描述才是產品該有的固有屬性。

至於客戶,應該是用訂單類來把他們聯系在一起。

關注行為分離

跟上面講的一樣,行為也應該是事物或對象的固有的本身的行為,明顯偏離原來行為的,應該考慮成另外的關注點兒分離開。

比如有一個函數叫做CreateNewCustomer(),那么CreateNewCustomer的行為就應該限定在創建一個新客戶上面,給新客戶自動發優惠券的動作就不能放到這個函數里面。

擴展分離

如果基於某種設計,原先不具有某些行為需要增加,可以考慮通過擴展或插件的形式來完成,將這些功能放入到插件或擴展中,就是擴展分離。

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

委托分離

如果某個行為還無法具體確定,可以使用委托的方式。
比如C#的delegate,當我們還不知道某些具體行為應該如何實現,或者不應該在此處對該行為進行實現,或者有多個行為可以互相替代,就可以將函數的參數指定為一個delegate。

至於delegate具體怎樣實現,那是其他部分應該關注的點。

比如現在需要將Customer的信息持久化,就可以把這個請求委托給DatabaseManager或WebSerivceManager,由他們自行處理數據,然后返回給我結果。

反轉分離

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

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

在實際的開發過程中,沒有東西是一成不變的,而層次和架構也應該是在開發的過程里面不斷完善和重構。

初級程序員最煩的是需求或業務的修改,一些我們覺得奇奇怪怪的修改導致大家不斷的修改代碼,心里很煩,在心里也默默的把產品經理被翻過來倒過去罵了千百遍。

但是,在實際的工作中你會發現,軟件開發就是這樣,沒有什么是不變的。

如果一定要找出一個不變的點,我想那應該是:

唯一不變的,就是變化。

關於不斷的修改與重構,也可以參考《重構-改善既有代碼的設計》,記得封面上寫的是:

軟件開發的不朽經典
生動闡述重構原理和具體做法
普通程序員進階到編程高手必須修煉的秘笈

呃,再往下面離題越來越遠了。
至此,關注點分離這塊內容暫告一段落。

小春微信 小春 原創內容 本文地址:http://www.cnblogs.com/asis/p/architecture-Soc.html https://1few.com/architecture-Soc/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM