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