帶你領略Clean架構的魅力

前言

當項目需求不斷擴張的時候,當開發團隊人員不斷增長,當新技術不斷涌現,當軟件質量不斷提升,我仍是不能和你分手,不能和你分手。我對唱出聲的同窗不發表任何意見。若是你真的碰到上述問題而沒有演進你的架構,可能你碰到的問題都是屬於靈異事件。那這裏的核心點是架構,那它又是個什麼玩意?它能帶來什麼好處?html

架構

到底什麼是架構?我如今的水平還不能告訴你,沒資格。我能告訴你本身在學習過程當中的領悟,我想架構就是一種約定,怎樣的約定?爲了更好的研發效率、擴展性和穩定性,更精準的風險防控能力。這樣說可能有點抽象。java

做爲一名資深宅男,牀到門就是世界上最遙遠的距離,上一次廁所好像經歷了九九八十一難,但咱們從不寂寞,你說是吧,Mac。額,好像扯遠了,我用完東西可能一直放在我喜歡的地方,只是在其餘人眼中顯得有點亂,在我眼裏是頗有規律的。由於我一直遵循着這個規定,每本書都有我給它定義的位置。可是我老媽不知道啊,雖然整理的很乾淨,可是書放錯了位置,老媽多是無心識的,就算下次我問她,她也記不清了。爲了找到這本書,我也只能遍歷一遍了。若是咱們雙方都遵循咱們倆一塊兒定義的一個規定,一個約定,達成一種共識。那麼就很簡單了,書永遠在那,就算是添新書仍是移除,雙方都有章可循。android

因而可知,架構的好處就是除了引進新的技術,本身或者說產品自己都有更好的體驗外,還因爲作了統一規範,讓結構更加清晰,健壯,團隊協做更加方便。git

以上並非今天的主題,架構的理解也僅限於個人理解,相對於Android,咱們知道的架構更多的可能叫MVC、MVP和MVVM等。關於這個。。。對方不想和你說話,並向你扔了一個連接。一篇好的文章是由文章自己內容和優秀的評論組成的,因此,你們慢慢欣賞,算了,買一送一,喜歡研究架構的同窗戳這裏,谷歌爸爸的。這裏,我直接引出今天的主題Clean架構。github

Clean架

大多數狀況下,碰到問題,咱們要從3個方向去思考,what、how、why。引用某大佬的一句話:未經思考的人生是不值得去過的人生。因此,列位看官不要僅僅知足於快餐文化,常常多動腦子,看問題千萬不要流於表面!額,又扯遠了。。。我先說說what。api

What

概念一直都是枯燥乏味的,若是不喜歡的朋友,能夠直接跳到How或者本章節的總結部分,可是概念也是最基礎的,最基礎是否是最重要我不發表意見。bash

秉承咱們No picture,say a J8的優雅傳統,先上個毫無心義的結構圖。架構

這張圖可能對於大家小白看來以爲很難以想象,但對於咱們專業來講,也是一臉懵逼(手動滑稽),我簡單的解釋下:mvc

  • Enterprise Business Rules:業務對象
  • Application Business Rules:用於處理咱們的業務對象,業務邏輯所在,也稱爲Interactor
  • Interface Adapters: 接口轉換,拿到咱們須要的數據,表現層(Presenters)和控制層(Controllers)就在這一層
  • Frameworks and Drivers: 這裏是全部具體的實現了:好比:UI,工具類,基礎框架等等。

關於上面的圖,米娜能夠戳這裏app

我解釋後估計你仍是一頭霧水,咱們再來看一個圖:

好像相對於上面那張圖更好理解,知道爲何嗎?由於字少了好多。哈哈。接下來的內容以及個人開源項目中都是以此爲基礎來寫的。分別來解釋下。

表現層 (Presentation Layer)

咱們這裏的表現層以MVP爲基礎,我的以爲Clean自己也是MVP的基礎上更加抽象,更加獨立。熟悉的MVP的同窗很是清楚這一層是幹嗎用的。老規矩,先上張圖。

是否是很眼熟?P層使得V層(Fragment和Activity)內部除UI邏輯再無其它邏輯。而個人開源項目中的Presenter由多個Interactor組成。底下會介紹。

領域層 (Domain Layer)

圖上很明顯了,這裏主要是interactor的實現類和業務對象。講道理這裏應該只屬於java模塊,可是有時候咱們的業務對象,可能要實現第三方庫中的實體類接口,不得不改成Android模塊,暫時沒想到很好的辦法,有知道的大佬能夠指教一下。

數據層 (Data Layer)

這是一種Repository模式,具體的能夠看這裏。以我如今的看法,只能說只要項目複雜而須要分層,那麼就應該用這個模式,它讓clean架構的clean更加亮眼。

這個原本就是概念,我相信你們也不肯意看,因此就簡單介紹。若是想詳細瞭解,能夠戳這裏

總結

如今談談本身的見解,後者是相對前者較爲具體的一種符合Android的結構。在這插一個clean架構的依賴性規則:內層不能依賴外層。三者也都分別解釋了是幹什麼用的,那麼爲何有分爲這三者,它們又有什麼聯繫?我是個俗人,那就應該用俗話來說,從數據層利用Repository模式讓領域層感受不到數據訪問層的存在,即原始數據是獨立的,業務規則不綁定具體哪種數據,通俗點講就是你要什麼數據?我給你取,但你不須要知道我從哪裏取的;所以領域層對數據層怎麼實現的是一無所知,而領域層主要工做就是你給了我數據,那我就要用,怎麼用?都是我來決定;用完以後再回調給表現層渲染UI。所以大多數的業務邏輯都在領域層,能夠說是一個APP的核心。我認爲這裏透露着一個很重要的設計理念就是數據驅動UI,我都想給本身點個贊,哈哈。其實,到這裏,你內心已經有點13數的話,能夠跳到Why,由於怎麼用已是具體的東西,而架構自己就是一種共識,是抽象的,從Java角度講你能夠多個類去實現這個接口。下面的使用只是我對Clean架構理解的一點代碼體現。

How

下面的例子是從我開源庫CrazyDaily中選取的,以知乎日報爲例。

數據層 (Data Layer)

數據層就是從咱們的倉庫(Repository)中取數據,能夠從雲端、磁盤或者內存中取。

public interface ZhihuService {
    String HOST = "http://news-at.zhihu.com/api/4/";

    @GET("news/latest")
    Flowable<ZhihuNewsEntity> getZhihuNewsList();

    @GET("news/{id}")
    Flowable<ZhihuNewsDetailEntity> getZhihuNewsDetail(@Path("id") long id);
}

public class ZhihuDataRepository implements ZhihuRepository {
    ...
    @Inject
    public ZhihuDataRepository(HttpHelper httpHelper) {
        mZhihuService = httpHelper.getZhihuService();
    }
    @Override
    public Flowable<ZhihuNewsEntity> getZhihuNewsList() {
        return mZhihuService.getZhihuNewsList()
        ...
    }
    ...
}複製代碼

這裏比較尷尬的是隻提供了雲端的數據,採用的是retrofit+okhttp的框架獲取。比較正確的方式應該是給ZhihuDataRepository提供一個Factory而不是HttpHelper,Factory根據不一樣的條件獲取相應的數據。好比像這樣:

@Inject
  UserDataRepository(UserDataStoreFactory dataStoreFactory,
      UserEntityDataMapper userEntityDataMapper) {
    this.userDataStoreFactory = dataStoreFactory;
    this.userEntityDataMapper = userEntityDataMapper;
  }複製代碼

UserDataStoreFactory是從不一樣地方獲取數據的一個工廠類,UserEntityDataMapper是咱們的數據包裝類,不知道還記得上面的Interface Adapters嗎?細心的朋友能夠關注到ZhihuDataRepository實現了ZhihuRepository,可是ZhihuRepository並不是數據層的東西,而是領域層的東西,很顯然,以接口進行關聯,但內容獨立,沒錯,這就是傳說中的依賴倒置原則。

領域層 (Domain Layer)

public interface ZhihuRepository {

    Flowable<ZhihuNewsEntity> getZhihuNewsList();

    Flowable<ZhihuNewsDetailEntity> getZhihuNewsDetail(long id);
}

public abstract class UseCase<T, Params> {

    ...

    public UseCase() {
        ...
    }

    protected abstract Flowable<T> buildUseCaseObservable(Params params);

    public void execute(Params params, DisposableSubscriber<T> subscriber) {
        ...
    }
    ...
}

public class ZhihuNewsListUseCase extends UseCase<ZhihuNewsEntity, Void> {

    private final ZhihuRepository mZhihuRepository;

    @Inject
    public ZhihuNewsListUseCase(ZhihuRepository zhihuRepository) {
        mZhihuRepository = zhihuRepository;
    }

    @Override
    protected Flowable<ZhihuNewsEntity> buildUseCaseObservable(Void aVoid) {
        return mZhihuRepository.getZhihuNewsList()
        ...
    }
}複製代碼

真的很完美,跟數據層一毛線關係都沒有,利用接口(ZhihuRepository)來控制數據層(ZhihuDataRepository)。真的感受架構愈來愈有意思了。我能夠在這裏處理咱們大部分的業務邏輯。

表現層 (Presentation Layer)

@ActivityScope
public class HomePresenter extends BasePresenter<HomeContract.View> implements HomeContract.Presenter {

    private ZhihuNewsListUseCase mZhihuUseCase;
    ...

    @Inject //多個UseCase
    public HomePresenter(ZhihuNewsListUseCase zhihuUseCase ...) {
        mZhihuUseCase = zhihuUseCase;
        ...
    }

    @Override
    public void getZhihuNewsList() {
        mZhihuUseCase.execute(new BaseSubscriber<ZhihuNewsEntity>() {
            @Override
            public void onNext(ZhihuNewsEntity zhihuNewsEntity) {
                mView.showZhihu(zhihuNewsEntity);
            }
        });
    }
}

public interface HomeContract {

    interface View extends IView {

        void showZhihu(ZhihuNewsEntity zhihuNewsEntity);
        ...
    }

    interface Presenter extends IPresenter<View> {

        void getZhihuNewsList();
        ...
}

public class HomeActivity extends BaseActivity<HomePresenter> implements HomeContract.View {

    @Override
    protected void initData() {
        mPresenter.getZhihuNewsList();
        ...
    }

    @Override
    public void showZhihu(ZhihuNewsEntity zhihuNewsEntity) {
         ...
    }
    ...
}複製代碼

說實話真的不想貼代碼,太麻煩了,但不貼,不太好理解,而與咱們相濡以沫的也就是代碼了,眼睛莫名一酸。表現層更多的是MVP的概念,因此。。

簡單的理下邏輯,Activity發起獲取數據信號(View)->調用Presenter接口(Presenter)->調用UseCase接口(Domain)->調用Repository接口(Data)->拿到原始數據->回調Repository(Data)->回調UseCase(Domain)->回調Presenter(Presenter)->回調Activity(View)

若是這都看到不懂,買塊豆腐撞死算了。

Why

其實How並非很重要,但卻佔了很大篇幅。

你認爲Why是最重要的嗎?這個問題留在心中,先來看看Why。

  • Easy to maintain
  • Easy to test
  • Very cohesive
  • Decoupled

看見高內聚,低耦合我就頭疼。說說其它吧,易於維護,這樣的結構已經能說明了,易於測試也好理解,各個模塊獨立,來看看這:

  • 展現層 (Presentation Layer) : 使用android instrumentation和espresso進行集成和功能測試
  • 領域層 (Domain Layer) :使用JUnit和Mockito進行單元測試
  • 數據層 (Data Layer) :使用Robolectric(由於依賴於Android SDK中的類)進行集成測試和單元測試

說來慚愧,嫌麻煩,我在開源項目裏並無寫測試,相信我之後會加的,我也不是那種不負責任的人,獻上大佬的一個關於clean的開源項目Android-CleanArchitecture

題外騷話

關於clean的差很少到這裏結束了,若是有什麼問題,能夠聯繫我,一塊兒討論。先喝一碗雞湯爲敬,學會平靜的對待生活中的不完美之處,適應本身的情緒,瞭解如何讓它們天然宣泄出去。說來也可笑,個人一個庫MTRVA也受到了我學習架構時的影響,它是RecyclerViewAdapter的至關於Presenter層的一個東西,咱們老是免不了在Adapter中對資源或者說數據的處理,這就跟Activity一鍋粥同樣,它讓你只關注UI邏輯。有人說,個人界面簡單,啥都不用算,給我list,setAdapter,搞定。額。。。那確實不用。同理,簡單的項目也並不須要什麼複雜的架構,相信從頭看到尾的同窗,很明顯的看出clean架構的缺點,就是繁瑣。架構本然就是在需求中不斷演進。祝你可以搭建屬於大家的架構。最後,感謝一直支持個人人!

傳送門

Github:github.com/crazysunj/

博客:crazysunj.com/

相關文章
相關標籤/搜索