The Clean Architecture

Robert C. Martin (Uncle Bob)html

原文:https://blog.cleancoder.com/u...
譯:祝坤榮java

clipboard.png

在過去幾年咱們看到關於系統架構的不少想法。這些包括:web

儘管這些架構在一些細節上都有不一樣,它們還是類似的。他們都有一樣的目標,隔離關注點。他們都經過將軟件分層來達到隔離。每一個都至少有一層業務規則,另外一層做爲接口。數據庫

每一個這些架構產出的系統都是:安全

  1. 獨立的框架。架構不依賴一些存在類庫的特性。這樣你能夠像工具同樣使用這種框架,而不須要讓你的系統受到它的約束條件。
  2. 可測試。業務規則能夠脫離UI,數據庫,web服務器或其餘外部元素進行測試。
  3. 獨立的UI。UI能夠很容易的更換,系統的其餘部分不須要變動。例如,Web UI能夠被換成控制檯UI,不須要變動業務規則。
  4. 獨立的數據庫。你能夠交換Oracle或SQL Server,用於Mongo,BigTable,CouchDB或其餘的東西。你的業務規則不與數據庫綁定。
  5. 獨立的外部代理。實際你的業務規則並不知道關於外部世界的任何事情。

這篇文章上面的圖試着將以上全部架構整合成一個可執行的想法。服務器

依賴規則

同心圓表示軟件的不一樣部分。大致上,你走的越遠,軟件的級別更高。外部的圓是機制,內部的圓是策略。微信

讓這個架構工做的覆蓋規則是依賴規則。這個規則說明了源代碼依賴只能向內。內部圓不能知道任何外部圓的事。實踐中,外部圓裏一些聲明的名字不能被內部圓裏的代碼提到。這包括,函數,類,變量或其餘任何軟件實體。網絡

一樣的,外部圓使用的數據格式不該該被內部圓使用,尤爲是當這些格式是被外部圓使用的框架生成的時候。咱們不想讓外部圓的東西影響到內部圓。數據結構

實體

實體封裝企業域範圍的業務規則。實體能夠是一個有方法的對象,也能夠是一組數據結構和函數。只要企業裏不一樣的應用可使用這些實體就能夠。架構

若是你不是企業級,而只是寫一個單體應用,那麼這些實體就是應用的業務對象。它們封裝了最通用和高層的規則。當外部變化時它們基本不太會變化。例如,你不會認爲這些對象會由於頁面導航或安全方面的變化而改變。任何特定應用的操做都不該該影響實體層。

用例

這層的軟件包含特定應用的業務規則。它封裝並實現了系統的全部用例。這些用例組織了實體中的數據流向,並指揮這些實體使用他們的企業域業務規則來完成用例的目標。

咱們不指望這層影響實體。咱們也不但願這層會在如數據庫,UI,或其餘經常使用框架這樣的外部變化時被影響。這層隔離了以上關注點。

固然咱們指望對於應用操做的變化會影響用例而進一步影響到這層的軟件。 若是一個用例的細節變化了,那麼這層的代碼確定也會被影響。

接口適配器

這層的軟件是一組適配器,其將數據轉換成從用例和實體最合適的格式,到對於一些相似數據庫或網站這種外部設施最合適的格式。在這一層,舉個例子,會包含GUI的MVC架構。Presenters, Views,與Controllers都屬於這裏。模型基本就是從controllers傳遞到用例的數據結構,並從用例返回到presenters和views。

相似的,數據被轉換了,在這層,從對於實體和用例合適的結構,變成對於持久層框架使用的結構。這圈內的代碼不該該知道數據庫。若是數據庫是一個SQL數據庫,那麼全部SQL都應該在這層內,特別是此層與數據庫有關的部分。

這層其餘適配器也須要將數據從相似外部服務的外部的結構,轉換成用例和實體使用的內部結構。

框架與驅動

最外層主要組合了數據庫,網絡框架這樣的框架和工具。在這層你除了寫一些與內層環通訊的膠水代碼,基本不會有其餘代碼。

這層是全部細節存在的地方。網絡是細節。數據庫是細節。 咱們將這些東西放在外部保證它們不會影響其餘部分。

只有四個圈?

不是的,圓圈是個示意。你可能發現你須要不止4個。沒有規則說你必定要有四個。 實際上,依賴規則一直存在。源代碼依賴一直指向內部。當你向內部移動時抽象的層次在增長。最外部的圓是很低層的具體細節。當你內移時軟件變得更抽象,並封裝了高一級的策略規則。最內部的圓是最廣泛的抽象層級。

跨越邊界

在圖的右下方是咱們穿越圓圈邊界的示例。它展現了Controller和Presenter與下一層的用例進行通訊。注意控制流。它從controller出發,穿過用例,而後在presenter裏執行。也注意下源碼依賴。它們每一個都指向內部的用例。

咱們一般使用依賴反轉原則解決這個明顯的問題。在java這樣的語言中,咱們會整理源碼依賴與控制流相反的接口和繼承關係,讓它們從邊界正確的穿過。

例如,用例須要調用presenter。可是,這個調用不能直接進行由於會違反依賴規則。外圈的名字不能被內圈提到。因此咱們的用例調用內圈的一個接口(在這個例子裏是Use Case Output Port),並讓外圈的presenter實現它。

架構裏全部的邊界穿越都用這個技巧。咱們使用動態多態來建立與控制流相反的源碼依賴,以便於不管在控制流的任何方向都不會違反依賴規則

什麼樣的數據會穿越邊界

正常來講穿過邊界的數據是簡單數據結構。你可使用基本結構或簡單的Data Transfer 對象。或者能夠方便的進行函數賦值的數據。或者你能夠打包進一個hashmap,或者將它組裝成一個對象。重要的是穿過邊界的是隔離,簡單的數據結構。咱們不想搞變通傳遞實體或數據庫行數據。咱們不想數據結構有任何違反依賴規則的依賴。

例如,不少數據庫框架在查詢後返回一個方便的數據格式。咱們能夠叫它RowStructure(行結構)。咱們不想將這個行機構經過邊界傳遞給內部的圈。這會致使內部圈須要知道外部圈的內容進而違反依賴規則

因此當咱們在邊界傳遞數據是,要注意其應該是內部圈的格式。

結論

聽從這些簡單規則並不難,而且能幫你減小之後的問題。經過將軟件隔離分層,並聽從依賴規則,你能夠創建一個真正可測試的系統,包含了以上全部好處。當任何系統額外部部分過期了,好比數據庫或web框架,你能夠容易的替換這些過期的元素。

本文來自微信公衆號「麥芽麪包,id「darkjune_think」轉載請註明。交流Email: zhukunrong@yeah.net

相關文章
相關標籤/搜索