關於Clean Architecture在android中的應用


一、clean架構簡介


clean架構相信你們早有耳聞,畢竟是Bob大叔的心血之做,最近又把five.agency/blog/androi… 幾篇關於clean 架構的文章拿出來讀讀加深了對該架構的一些理解。java


clean架構又稱「洋蔥架構」,這個是因爲它的架構示意圖得名的android


image.png


刪除一些android項目中使用不到的東西加上咱們使用的東西看起來以下圖git

image.png




二、核心概念

從最抽象的核心到細節的邊緣github


Entities

Entities,即Domain 對象或業務對象,是App的核心。 它們表明了APP的主要功能, 它們包含業務邏輯, 他們不會與外在世界的細節進行互動。編程


Use cases設計模式

Use case,又名interactors(交互器),又名business services,是Entities的擴展,是業務邏輯的延伸,也就是說。 它們包含的邏輯不只限於一個實體,而是處理更多的實體。 網絡

Repositories

Repositories用於持久化Entities。 就這麼簡單。 它們被定義爲接口並用做想要對Entities執行CRUD操做的用例的輸出端口。架構

Presenters

若是你熟悉MVP模式,Presenters就會作你指望他們作的事情。 他們處理用戶交互,調用適當的業務邏輯,並將數據發送到UI進行渲染。 這裏一般有不一樣類型之間的映射app


大概這幾個概念能夠幫助咱們更好的理解clean 架構,可是核心一點就是越在洋蔥裏面越是抽象。dom


三、clean 架構的核心規則


首先須要掌握涉及的領域,原文稱做「Master of your domain」,就是說當你打開你的工程,除去技術相關,你就應該從宏觀上知曉你的app是作什麼的,而不要沉浸到細節之中" 爲啥須要咱們站在這個高度去看待本身的項目呢,由於這也是clean核心所在,該架構越往洋蔥裏面抽象度愈來愈高,都是業務邏輯的高度抽象,即"內層包含業務邏輯、外層包含實現細節"

繼而給出了設計出這樣特性的clean架構須要具有的技術點


(1)Dependency rule(依賴原則)

(2)Abstraction(抽象)

(3)Communication between layers(層之間的通訊)


下面將一一介紹


3.1 Dependency rule(依賴原則)


從最開始的第一幅咱們就能夠看出箭頭是"依賴",即 外層看到並瞭解內層,可是內層既看不到也不知道外層,結合前面所強調的 內層包含業務邏輯(抽象),外層包含實現細節。 結合依賴關係規則,業務邏輯既看不到,也不知道實現細節。 一般咱們能夠經過放在不一樣的module中去來調整它們之間的依賴關係


image.png



3.2 Abstraction(抽象)


以前也說過當你走向圖的中間時,東西變得更加抽象。 這是有道理的:抽象每每比細節更加穩定,就像搭積木同樣根基越穩越好。

舉個例子好比咱們能夠將抽象接口定義爲「加載網絡圖片」並將其放入內層,業務邏輯就可使用它來顯示圖片。 另外一方面,咱們能夠經過實現改接口調用具體的圖片加載庫glide或者Picasso,而後將該實現放入外層。業務邏輯可使用加載圖片功能而無需知道實現細節的任何內容。這樣抵禦了變化的風險,往後換成什麼方式加載圖片,洋蔥內部的抽象業務邏輯是不會感知到的


3.3 Communication between layers(層之間的通訊)


既然已經劃分好了層,分離了內容,將業務邏輯放在應用程序的架構中心和架構邊緣的實現細節中,一切看起來都很棒。 可是你可能很快遇到了一個有趣的問題。

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


組合和繼承的就要發揮功效了


image.png



四、實踐

下面用代碼示意一下,以RSS Reader 爲例咱們的用戶應該可以管理他們的RSS提要訂閱,從提要中獲取文章並閱讀它們。


這裏是數據流問題,用例介於表示層和數據層之間。 咱們如何創建層之間的溝通? 記住那些輸入和輸出端口?

image.png

從上圖能夠看出咱們的 Use Case必須實現輸入端口(接口)。 Presenter在 Use Case上調用方法,數據流向 Use Case(feedId)。 Use Case映射feedId提供文章並但願將它們發送回表示層。 它有一個對輸出端口(回調)的引用,由於輸出端口是在同一層定義的,所以它調用了一個方法。 所以,數據發送到輸出端口 - Presenter。


讓咱們從domain層開始,建立咱們的核心業務模型和邏輯。

咱們的商業模式很是簡單:

  • Feed - 持有RSS提要相關數據,如網址,縮略圖網址,標題和說明
  • Article -保存文章相關數據,如文章標題,網址和發佈日期

咱們的邏輯,咱們將使用UseCases。 他們在簡潔的類中封裝了小部分業務邏輯。 他們都將實施通用的UseCase 契約接口:

public interface UseCase<P, R> {

 interface Callback<R> {
 void onSuccess(R return);
 void onError(Throwable throwable);
 }

 void execute(P parameter, Callback<R> callback);
}



public interface CompletableUseCase<P> {

 interface Callback {
 void onSuccess();
 void onError(Throwable throwable);
 }

 void execute(P parameter, Callback callback);
}


複製代碼

UseCase接口是輸入端口,Callback接口是輸出端口,GetFeedArticlesUseCase實現以下

class GetFeedArticlesUseCase implements UseCase<Integer, List<Article>> {

 private final FeedRepository feedRepository;

 @Override
 public void execute(final Integer feedId, final Callback<List<Article>> callback) {
 try {
 callback.onSuccess(feedRepository.getFeedArticles(feedId));
 } catch (final Throwable throwable) {
 callback.onError(throwable);
 }
 }
 }複製代碼


而後到洋蔥外面的UI實現,View有一個簡單的契約類

interface View {

 void showArticles(List<ArticleViewModel> feedArticles);
 
 void showErrorMessage();
 
 void showLoadingIndicator();
}複製代碼

該視圖的Presenter具備很是簡單的顯示邏輯。 它獲取文章,將它們映射到view odels並傳遞到View,再看下FeedArticlesPresenter:

class FeedArticlesPresenter implements UseCase.Callback<List<Article>> {

 private final GetFeedArticlesUseCase getFeedArticlesUseCase;
 private final ViewModeMapper viewModelMapper;

 public void fetchFeedItems(final int feedId) {
 getFeedArticlesUseCase.execute(feedId, this);
 }

 @Override
 public void onSuccess(final List<Article> articles) {
 getView().showArticles(viewModelMapper.mapArticlesToViewModels(articles));
 }

 @Override
 public void onError(final Throwable throwable) {
 getView().showErrorMessage();
 }
 }複製代碼


到這裏能夠看出FeedArticlesPresenter實現了Callback接口,並將其自身傳遞給use case,它其實是use case的輸出端口,並以這種方式關閉了數據流


image.png


谷歌架構項目上也有個 todo-mvp-clean分支能夠看下具體玩法。


五、小結


這個跟設計模式中依賴倒置和接口隔離有着密不可分的關係,經過依賴倒置,只依賴於抽象而不是細節,將細節的實現倒置到實現類中,這樣洋蔥的核心就是清清爽爽的業務邏輯(抽象);

一般一個良好的架構通常須要知足如下幾點:

  1. Satisfy a multitude of stakeholders.(知足各方利益者)
  2. Encourage separation of concerns.(鼓勵的關注點分離)
  3. Run away from the real world (Android, DB, Internet…).即高度的抽象
  4. Enable your components to be testable.(使您的組件成爲可測試的)

可是一個架構每每針對特定的場景,架構也是須要慢慢演進的,好比後面的模塊化、插件化等等都是業務發展到必定程度,當前架構的弊端慢慢的凸顯須要更新。但無論如何變化,一些核心基本點仍是相伴相隨,好比依賴翻轉、面向接口編程、關注點分離等都是咱們須要點亮的技能點之一。


參考


一、five.agency/blog/androi…

二、five.agency/android-arc…

三、five.agency/android-arc…

相關文章
相關標籤/搜索