Android架構:第二部分-The clean architecture (譯)

在系列的第一部分中,咱們介紹了咱們在尋找可行的體系結構方面所犯的錯誤。 在這一部分中,咱們將介紹所謂的Clean Architecture.android

你在google「clean architecture」中遇到的第一個圖像是這樣的:數據庫

the clean architecture

它也被稱爲洋蔥架構,由於圖表看起來像一個洋蔥(當你意識到你須要寫多少樣板時,它會讓你哭泣); 或端口和適配器,由於您能夠看到右下角有一些端口。 六角形架構是另外一種相似的架構。架構

Clean architecture是前面提到的Bob叔叔的心血結晶,他也寫了關於Clean Code和Clean Coder的書籍。 這種方法的主要觀點是業務邏輯(也稱爲domain)處於宇宙的中心。app

Domain

當你打開你的項目,你應該已經知道這個APP是什麼。 其餘一切都是實現細節。 例如:持久性 - 這是一個細節。 定義一個接口,使內存實現一個快速而骯髒的實現,在業務完成以前不要考慮它。 而後,您能夠決定如何確實堅持數據。 數據庫,互聯網,組合,文件系統 - 也許把它們留在內存中,也許事實證實你根本沒必要堅持它們。 在一句話中:內層包含業務邏輯,外層包含實現細節。dom

這就是說,有一些Clean Architecture能夠實現這些功能:佈局

  1. Dependency rule(依賴規則)
  2. Abstraction(抽象)
  3. Communication between layers(層之間的通訊)

I. Dependency rule(依賴規則)

依賴關係規則能夠用下圖來解釋:google

graph-2

外層應該取決於內層。 紅色方塊中的這三個箭頭表示相關性。 「依賴」也許這是最好用的術語,如「看」,「知道」,或者「知道的。」沒那麼好。在這方面,外層看到並瞭解內層,但內層既不看也不知道外層。 如前所述,內層包含業務邏輯,外層包含實現細節。 結合依賴關係規則,業務邏輯既看不到,也不知道實現細節。 這正是咱們正在努力完成的。spa

您如何實現依賴關係規則取決於您。 您能夠將它放在不一樣的包中,但要當心不要使用「內部」包裝中的「外層」包裝。 可是,若是有人沒有意識到依賴性原則,沒有什麼能阻止他們打破它。 例如,更好的方法是將圖層分紅不一樣的Android模塊,並調整構建文件中的依賴關係,以便內層沒法使用外層。 在Five,咱們使用了二者之間的東西。blog

值得一提的是,儘管沒有人能夠阻止你跳過圖層 ,例如,在藍色圖層組件中使用紅色圖層組件。我強烈建議您僅訪問圖層旁邊的組件。繼承

II. Abstraction(抽象)

抽象原則已經暗示過。 當你走向圖的中間時,東西變得更加抽象。 這是有道理的:正如咱們所說的內圈包含業務邏輯,外圈包含實現細節。

clean android architecture

您甚至能夠在多個圖層之間劃分相同的邏輯組件,如上圖所示: 在內層中能夠定義更抽象的部分,外層中更具體的部分。

一個例子會說清楚:咱們能夠將抽象接口定義爲「通知」並將其放入內層,這樣,您的業務邏輯就可使用它來向用戶顯示通知。 另外一方面,咱們能夠經過實現使用Android通知管理器顯示通知的方式來實現該接口,而後將該實現放入外層。

經過這種方式,業務邏輯能夠在咱們的示例中使用功能通知 - 但它不知道實現細節的任何內容:實際通知是如何實現的。 並且,業務邏輯甚至不知道實現細節存在。 看看下面的圖片:

clean android architecture

將抽象與依賴規則結合起來時,事實證實,使用通知的抽象業務邏輯既沒有看到也沒有意識到使用Android通知管理器的具體實現。 這很好,由於咱們能夠切換具體實現,業務邏輯甚至不會注意到它。

讓咱們簡單地比較一下使用標準三層體系結構時抽象和依賴關係的外觀和工做方式。

graph-5

您能夠在圖中看到標準三層體系結構中的全部依賴關係都轉到數據庫。 這意味着抽象和依賴不匹配。 從邏輯上講,業務層應該是應用程序的中心,但不是,由於依賴關係會轉向數據庫。

業務層不該該知道數據庫。 而在清潔架構中,依賴關係轉到業務層(內層),而抽象層也向業務層上升,所以它們匹配得很好。

這很重要,由於抽象是理論,依賴是實踐。 抽象是應用程序的邏輯佈局,依賴關係是它如何組合在一塊兒。 在 clean architecture中,這二者匹配,而在標準的三層架構中則沒有; 若是你不當心,這可能會很快致使各類邏輯不一致和混亂。

III. Communication between layers(層之間的通訊)

如今咱們已經將應用程序劃分爲模塊,很好地分離了全部內容,將業務邏輯放在應用程序的中心和郊區的實現細節中,一切看起來都很棒。 可是你可能很快遇到了一個有趣的問題。

若是你的UI是一個實現細節,那麼internet就是一個實現細節,業務邏輯介於二者之間,咱們如何從internet獲取數據,經過業務邏輯傳遞它,而後將其發送到屏幕?

業務邏輯處於中間,應該在互聯網和用戶界面之間進行調解,但它甚至不知道這兩我的存在。 這是一個溝通和數據流的問題。

咱們但願數據可以從外層流向內層,反之亦然,但依賴性規則不容許這樣作。 讓咱們將其簡化爲最簡單的例子:

咱們只有兩層,綠色和紅色。 綠色的是外在的,知道紅色的,紅色的是內在的,只知道本身。 咱們但願數據從綠色流向紅色流,而後返回綠色流。 該解決方案以前已經被暗示過,以下圖所示:

clean android architecture

右下角的圖部分顯示了數據流。 數據從Controller經過Use Case(或用用戶選擇的組件替換用例)輸入端口,而後經過Use Case自己,而後經過Use Case輸出端口返回給Presenter。

圖的主要部分上的箭頭表示組成和繼承 - 組成和繼承 - 組成由一個實心箭頭表示,繼承由一個一個空箭頭表示。 組成也被稱爲有關係,而繼承是一種關係。 圓圈中的「I」和「O」表示輸入和輸出端口。 能夠看出,在綠色層中定義的控制器具備在紅色層中定義的輸入端口。 Use Case(齒輪,商業邏輯,如今不重要)是(或實現)輸入端口並具備輸出端口。 最後,在綠色層中定義的Presenter其實是在紅色層中定義的輸出端口。

咱們如今能夠將其與數據流相匹配。 Controller有一個輸入端口 - 它實際上有一個參考。 它調用一個方法,以便數據從Controller傳輸到輸入端口。 可是輸入端口是一個接口,實際的實現就是Use Case:因此它在一個Use Case上調用一個方法,數據流向Use Case。 Use Case作了一些事情,並但願將數據返回。 它有一個對輸出端口的引用 - 由於輸出端口是在同一層定義的 - 因此它能夠調用它的方法。 所以,數據進入輸出端口。 最後,Presenter是或實現輸出端口; 這是神奇的一部分。 因爲它實現了輸出端口,數據實際上流入了它。

訣竅是Use Case只知道它的輸出端口; 世界在這個輸出端口結束。 實施它取決於Presenter, 它可能已經被任何東西實現了,由於用例不知道或關心,而且只知道其層中的小世界。 咱們能夠看到,經過組合和繼承的組合,咱們可使數據在兩個方向上流動,儘管內層不知道他們正在與外部世界進行通訊。 快速瀏覽下圖:

clean android architecture

你能夠看到兩個箭頭都指向中間,就像依賴箭頭同樣。 那麼,這是合乎邏輯的。 根據依賴規則,這是惟一可行的方法。 外層能夠看到內層,但不是其餘方式。 惟一棘手的部分是,這是一種關係,雖然它指向中間,但會顛倒數據流。

請注意,定義其輸入和輸出端口是內層的責任,以便外層可使用它們與之創建通訊。 我已經說過這個解決方案已經在以前被暗示了,並且已經有了。 說明抽象的通知示例也是這種通訊的一個例子。 咱們在內層中定義了一個通知接口,業務邏輯可使用它向用戶顯示通知,但咱們也有一個在外層中定義的實現。 在這種狀況下,通知接口是業務邏輯的輸出端口,它用於與外部世界進行通訊 - 本例中的具體實現。 您沒必要爲您的類命名FooOutputPort或BarInputPort; 咱們命名只是爲了解釋這個理論。

總結

那麼,這是過於複雜,過分模糊的過分工程? 好吧,當你習慣它時很簡單。 這是必要的。 它使咱們可以在現實世界中實現良好的抽象/依賴匹配實際交流和工做。 也許這一切都讓人聯想到弦理論:理論上美觀,可是過於複雜,咱們仍然不知道它是否有效,但在咱們的案例中 - 它確實有效。:)

這就是這個系列的第二部分。 最後,第三部分,畢竟咱們已經瞭解了理論和體系結構,將涵蓋全部你須要瞭解的關於這些圖表上的標籤,或者換句話說 - 單獨的組件。 咱們將向您展現在Android上應用的真實生活Clean Architecture。

這是Android體系結構博客文章系列的一部分。您還能夠查看其餘部分:

Part 5: How to Test Clean Architecture

Part 4: Applying Clean Architecture on Android (Hands-on)

Part 3: Applying Clean Architecture on Android

Part 1: every new beginning is hard

相關文章
相關標籤/搜索