到目前爲止,在這個系列中,咱們已經介紹了一些初學者的錯誤,並經過了Clean架構。 在最後一部分中,咱們將介紹拼圖的最後一部分:標籤,或者更確切地說:組件。android
首先,我將刪除咱們在Android項目中不使用的東西,而後添加一些咱們使用的東西,但在原始的Bob叔叔圖中找不到。 它看起來像這樣:數據庫
我會從最抽象的中心走到邊緣。緩存
Entities,即Domain 對象或業務對象,它們是App的核心。 它們表明了APP的主要功能,您應該可以經過查看它們來了解APP的功能。 它們包含業務邏輯,但僅限於它們 - 驗證和相似的東西。 他們不會與外在世界的細節進行互動,也不會處理持久性。 例如,若是您有新聞APP,則這些實體將是類別,文章和商業廣告。架構
Use case,又名interactors,又名business services,是Entities的擴展,是業務邏輯的延伸,也就是說。 它們包含的邏輯不只限於一個實體,而是處理更多的實體。 一個好Use case的一個指標是,你能夠用一種通用的語言描述它在一個簡單的句子中的做用 - 例如,「從一個帳戶轉移到另外一個帳戶」。你甚至能夠用這樣的命名來命名該類,例如,TransferMoneyUseCase。app
Repositories用於堅持Entities。 就這麼簡單。 它們被定義爲接口並用做想要對Entities執行CRUD操做的用例的輸出端口。 另外,它們能夠公開一些與持久性相關的更復雜的操做,例如過濾,聚合等。 具體的持久性策略,例如數據庫或因特網,是在外層實現的。 例如,您能夠命名接口AccountRepository。dom
若是你熟悉MVP模式,Presenters就會作你指望他們作的事情。 他們處理用戶交互,調用適當的業務邏輯,並將數據發送到UI進行渲染。 這裏一般有不一樣類型的模型之間的映射。 有些人會在這裏使用Controller,這很好。 咱們使用的Presenter正式被稱爲監督Controller。 咱們一般在每一個屏幕上定義一個或兩個Presenters,具體取決於屏幕,Presenter的生命週期與視圖的生命週期相關聯。 一條建議:嘗試在Presenter上將您的方法命名爲技術不可知論者(technology agnostic)。 假設您不知道視圖實現的技術。所以,若是您在視圖中具備名爲onSubmitOrderButtonClicked和onUserListItemSelected的方法,則處理這些事件的相應演示者方法能夠命名爲submitOrder和selectUser。測試
這個組件在通知(再次)例子中已經被取笑了。它包含了諸如傳感器,警報,通知,播放器,各類Managers等Android提供東西的實現。它是一個由兩部分組成的部分。第一部分是業務邏輯用做與外部世界進行通訊的輸出端口的內部圈定義的接口。第二部分,這是在圖中繪製的,是這些接口的實現。所以,您能夠定義例如名爲Gyroscope,Alarm,Notifications和Player的接口。注意名稱是抽象的和技術不可知(technology agnostic)的。業務邏輯不關心如何顯示通知,玩家如何播放聲音,或陀螺儀數據來自何處。您能夠製做將通知寫入終端,將聲音數據寫入日誌或從預約義文件收集陀螺儀數據的實現。這樣的實現對於調試或建立肯定性環境是很是有用的。可是,您固然必須製做諸如AndroidAlarm,NativePlayer等實現。在大多數狀況下,這些實現只是圍繞Android的Manager 類的包裝。fetch
將存儲庫的實現放在這個組件中。全部這些底層持久化的東西應該在這裏:DAO,ORM的東西,Retrofit(或別的東西)的東西,JSON解析等。你也能夠在這裏實現緩存策略,或者只是使用內存中的持久性,直到完成與應用程序的其他部分。咱們最近在團隊中進行了一次有趣的討論。問題是這樣的:資源庫是否應公開諸如fetchUsersOffline(fetchUsersFromCache)和fetchUsersOnline(fetchUsersFromInternet)之類的方法?換句話說,業務邏輯應該知道數據來自哪裏?看過這篇文章的全部內容後,答案很簡單:不。可是有一個問題!若是關於數據源的決定是業務邏輯的一部分 - 例如,若是用戶能夠選擇它,或者若是您有明確的離線模式的應用程序,那麼您能夠添加這樣的區別。可是我不會爲每一個抓取定義兩種方法。我可能會在資源庫中公開方法,如enterOfflineMode和exitOfflineMode。或者,若是它適用於全部存儲庫,則可使用輸入和退出方法定義OfflineMode接口,並在業務邏輯端使用它,讓存儲庫查詢該模式並在內部進行肯定。spa
將與Android用戶界面相關的全部內容放在這裏 Activities,fragments,views,adapters等完成。設計
下圖顯示了咱們如何將全部這些組件分紅Android Studio模塊。 你可能會發現另外一個更合適的部門。
咱們將entities,use cases,repositories和device接口分組到domain模塊中。 若是您想得到額外的挑戰,並得到永恆的榮耀和徹底乾淨的設計,您可使該模塊成爲純Java模塊。 它會阻止你在這裏使用快捷方式並將相關的東西放在Android上。
device模塊應該包含與Android相關的全部內容,而不是數據持久性和UI。 正如咱們已經說過的,data模塊應該包含與數據持久性相關的全部內容。 你不能讓這兩我的進入Java模塊,由於他們須要訪問各類Android的東西。 你能夠將它們變成Android庫。
最後,咱們將與UI相關的全部內容(包括presenters)分組到UI模塊中。 您能夠明確地命名爲UI,但因爲Android中的全部東西,咱們將其命名爲「app」,就像Android Studio在建立項目時命名的那樣。
爲了回答這個問題,我會拋棄Bob叔叔的圖表,並將以前描述的組件擴展到像咱們用來評估之前類型的體系結構的圖表。 這樣作後,咱們獲得這個:
如今讓咱們應用咱們在之前的體系結構中使用的相同條件。
它徹底由模塊級別,封裝級別和類級別分開。 因此SRP應該獲得知足。
咱們儘量將Android和現實世界推到了最外面。 業務邏輯再也不直接接觸Android。
咱們有很好的分離類,很容易測試。 接觸世界的類可使用Android測試用例進行測試; 可使用JUnit測試它。 有人惡意可能會稱這類爆炸。 我稱之爲可測試的。:)
我但願我精心挑選的標準並非爲了支持Clean架構而編造的,它會讓你嘗試一下。 這看起來很複雜,並且這裏有不少細節,但它是值得的。 一旦你將全部東西鏈接起來,測試就容易得多,錯誤更容易隔離,新特性易於添加,代碼更具可讀性和可維護性,一切正常,世界滿意。
因此,就是這樣。 若是您尚未這樣作,請查看之前的系列文章:Mistakes 和 Clean Architecture.。 若是您有任何意見或問題,請在下面留言。 咱們老是有興趣聽到你的想法。
閱讀咱們的Android Architecture系列的第四部分。
您還能夠查看其餘部分:
Part 5: How to Test Clean Architecture