整洁架构
本文是關于Bob大叔關于整潔架構的一篇學習筆記。
前言
整潔架構(Clean Architecture)是由Bob大叔在2012年提出的一個架構模型,顧名思義,是為了使架構更簡潔。
?
在開始深入的介紹這個架構之前,Bob大叔首先提到了
近些年來比較流行的一個系統架構,包括Hexagonal Architecture,Onion Architecture,以及他自己以前提出的Screaming architecuture等。并且著中說道通過這些架構產生的系統特點是:
- 獨立的框架. 這樣的架構并不依賴與應用軟件的具體庫包,這樣可以將框架作為工具,而不必將你的系統都胡亂混合在一起。
- 可測試. 業務規則能夠在沒有UI和數據庫 或Web服務器的情況下被測試。
- UI的獨立性. UI改變變得容易,不必改變系統的其余部分,一個Web UI能被一個控制臺或專門的圖形UI替代, 這些讀不必更改業務核心規則。
- 數據庫的獨立性. 你能夠在Oracle或SQL Server Mongo, BigTable, CouchDB,或之間切換, . 你的業務規則不會和數據庫綁定
- 獨立的外部代理,其實你的業務規則可以對其外面的技術世界毫無所知,比如是否使用了MVC或DCI都可以不關心。
好的,接下來一起了解一下clean architecture:
依賴規則(Dependency Rule)
用一組同心圓來表示軟件的不同領域。一般來說,越深入代表你的軟件層次越高。外圓是戰術是實現機制(mechanisms),內圓的是核心原則(policy)。
Policy means the application logic.
Mechanism means the domain primitives.
使此體系架構能夠工作的關鍵是依賴規則。這條規則規定軟件模塊只能向內依賴,而里面的部分對外面的模塊一無所知,也就是內部不依賴外部,而外部依賴內部。同樣,在外面圈中使用的數據格式不應被內圈中使用,特別是如果這些數據格式是由外面一圈的框架生成的。我們不希望任何外圓的東西會影響內圈層
實體 (Entities)
實體封裝的是整個企業范圍內的業務核心原則(policy),一個實體能是一個帶有方法的對象,或者是一系列數據結構和函數,只要這個實體能夠被不同的應用程序使用即可。
如果你沒有編寫企業軟件,只是編寫簡單的應用程序,這些實體就是應用的業務對象,它們封裝著最普通的高級別業務規則,你不能希望這些實體對象被一個頁面的分頁導航功能改變,也不能被安全機制改變,操作實現層面的任何改變不能影響實體層,只有業務需求改變了才可以改變實體
用例 (Use case)
在這個層的軟件包含只和應用相關的業務規則,它封裝和實現系統的所有用例,這些用例會混合各種來自實體的各種數據流程,并且指導這些實體使用企業規則來完成用例的功能目標。
我們并不期望改變這層會影響實體層. 我們也不期望這層被更外部如數據庫 UI或普通框架影響,而這也正是我們分離出這一層來的原因所在。
然而,應用層面的操作改變將會影響到這個用例層,如果需求中用例發生改變,這個層的代碼就會隨之發生改變。所以可以看到,這一層是和應用本身緊密相關的
接口適配器 (Interface Adapters)
這一層的軟件基本都是一些適配器,主要用于將用例和實體中的數據轉換為外部系統如數據庫或Web使用的數據,在這個層次,可以包含一些GUI的MVC架構,表現視圖 控制器都屬于這個層,模型Model是從控制器傳遞到用例或從用例傳遞到視圖的數據結構。
通常在這個層數據被轉換,從用例和實體使用的數據格式轉換到持久層框架使用的數據,主要是為了存儲到數據庫中,這個圈層的代碼是一點和數據庫沒有任何關系,如果數據庫是一個SQL數據庫, 這個層限制使用SQL語句以及任何和數據庫打交道的事情。
框架和驅動器
最外面一圈通常是由一些框架和工具組成,如數據庫Database, Web框架等. 通常你不必在這個層不必寫太多代碼,而是寫些膠水性質的代碼與內層進行粘結通訊。這個層是細節所在,Web技術是細節,數據庫是細節,我們將這些實現細節放在外面以免它們對我們的業務規則造成影響傷害
只有四個圈層嗎?
這個圓圈圖是示意性的。您可能會發現您需要的不僅僅是這四個。也沒有規定說你必須始終只有這四個。然而,依賴規則始終適用。源代碼的依賴關系總是由外向內。當你越向內時,抽象水平越高。而最外面的一圈是低層次的具體細節。當你越向內時軟件變得越為抽象,封裝了更高層次的策略。
跨邊界流程 (Crossing boundaries)
在圖的右下方是我們如何越過圓邊界的例子。它顯示控制器和Presenters之間是如何和用例進行通信的。注意控制流程。它開始于控制器,通過用例,然后在界面處執行。還要注意源代碼的依賴關系。他們中的每一個點都是指向內部用例。
那么,從圖中可以看到use case需要訪問Presenters,也就是內部的模塊需要訪問外部模塊,那么內部的模塊就需要知道外面模塊的一些細節,這違反了剛剛提到的只能向內依賴的原則!
如何解決呢??通常我們會使用依賴倒置原則來解決這種沖突。具體的實現方式可以是定義接口來表示外層的對象,然后在內層中調用接口而不是直接調用外層的類(否則會破壞依賴原則),而外層需要做的就是去實現這個接口。
首先需要理解的是Ownership inversion,也就是將本來在內層提供的功能定義在外層的接口中,而內層去實現這些接口。
一個示意圖如下:
?
再來看一個更加具體的例子:假設一個應用要調用一個庫,那么直接的方法是直接調用這個庫提供的方法。但是更好的設計是將這個庫提供的服務抽象成接口包含在調用應用中,而庫需要做的事情是去實現這些接口,示例如下:
那么什么數據可以跨層流動呢?
通常跨層的數據是簡單的數據結構。如果你喜歡你可以使用基本結構或簡單的數據傳輸對象DTO?;蚩梢院瘮悼梢哉{用數據參數?;蛘吣憧梢源虬焦1碇?#xff0c;或為它建構一個對象。最重要是跨層傳遞是孤立的、 簡單的數據結構。
我們不想讓這個數據結構是一個實體或數據庫記錄,因為我們不希望它們有任何的依賴關系,這會違反了依賴規則。例如,許多數據庫框架在查詢響應中返回一個方便的數據格式。我們可能會要求這對這個記錄重構,因為我們不想要跨層向內傳遞數據庫記錄。這就違反了依賴規則,它會迫使內圈要知道關于外圈的東西。所以當我們跨層傳遞數據,它總是以對內圈最方便的形式。
總結
Clean architecture的核心就是依賴原則。外圈的層次可以依賴內層,反之不可以,內圈核心的實體代表業務,不可以依賴其所處的技術環境。這樣做的最大好處是當系統的外部模塊不得不改變時(比如,替換已有的過時的數據庫系統),系統的內層模塊不需要做任何改變。
參考
The Clean Architecture
Dependency inversion principle
總結
- 上一篇: Zookeeper集群脑裂问题
- 下一篇: Git命令按人统计提交次数和代码量