当项目需求不断扩张的时候,当开发团队人员不断增长,当新技术不断涌现,当软件质量不断提升,我仍是不能和你分手,不能和你分手。我对唱出声的同窗不发表任何意见。若是你真的碰到上述问题而没有演进你的架构,可能你碰到的问题都是属于灵异事件。那这里的核心点是架构,那它又是个什么玩意?它能带来什么好处?html
到底什么是架构?我如今的水平还不能告诉你,没资格。我能告诉你本身在学习过程当中的领悟,我想架构就是一种约定,怎样的约定?为了更好的研发效率、扩展性和稳定性,更精准的风险防控能力。这样说可能有点抽象。java
做为一名资深宅男,床到门就是世界上最遥远的距离,上一次厕所好像经历了九九八十一难,但咱们从不寂寞,你说是吧,Mac。额,好像扯远了,我用完东西可能一直放在我喜欢的地方,只是在其余人眼中显得有点乱,在我眼里是颇有规律的。由于我一直遵循着这个规定,每本书都有我给它定义的位置。可是我老妈不知道啊,虽然整理的很干净,可是书放错了位置,老妈多是无心识的,就算下次我问她,她也记不清了。为了找到这本书,我也只能遍历一遍了。若是咱们双方都遵循咱们俩一块儿定义的一个规定,一个约定,达成一种共识。那么就很简单了,书永远在那,就算是添新书仍是移除,双方都有章可循。android
因而可知,架构的好处就是除了引进新的技术,本身或者说产品自己都有更好的体验外,还因为作了统一规范,让结构更加清晰,健壮,团队协做更加方便。git
以上并非今天的主题,架构的理解也仅限于个人理解,相对于Android,咱们知道的架构更多的可能叫MVC、MVP和MVVM等。关于这个。。。对方不想和你说话,并向你扔了一个连接。一篇好的文章是由文章自己内容和优秀的评论组成的,因此,你们慢慢欣赏,算了,买一送一,喜欢研究架构的同窗戳这里,谷歌爸爸的。这里,我直接引出今天的主题Clean架构。github
大多数状况下,碰到问题,咱们要从3个方向去思考,what、how、why。引用某大佬的一句话:未经思考的人生是不值得去过的人生。因此,列位看官不要仅仅知足于快餐文化,常常多动脑子,看问题千万不要流于表面!额,又扯远了。。。我先说说what。api
概念一直都是枯燥乏味的,若是不喜欢的朋友,能够直接跳到How或者本章节的总结部分,可是概念也是最基础的,最基础是否是最重要我不发表意见。bash
秉承咱们No picture,say a J8的优雅传统,先上个毫无心义的结构图。架构
这张图可能对于大家小白看来以为很难以想象,但对于咱们专业来讲,也是一脸懵逼(手动滑稽),我简单的解释下:mvc
关于上面的图,米娜能够戳这里。app
我解释后估计你仍是一头雾水,咱们再来看一个图:
好像相对于上面那张图更好理解,知道为何吗?由于字少了好多。哈哈。接下来的内容以及个人开源项目中都是以此为基础来写的。分别来解释下。
咱们这里的表现层以MVP为基础,我的以为Clean自己也是MVP的基础上更加抽象,更加独立。熟悉的MVP的同窗很是清楚这一层是干吗用的。老规矩,先上张图。
是否是很眼熟?P层使得V层(Fragment和Activity)内部除UI逻辑再无其它逻辑。而个人开源项目中的Presenter由多个Interactor组成。底下会介绍。
图上很明显了,这里主要是interactor的实现类和业务对象。讲道理这里应该只属于java模块,可是有时候咱们的业务对象,可能要实现第三方库中的实体类接口,不得不改成Android模块,暂时没想到很好的办法,有知道的大佬能够指教一下。
这是一种Repository模式,具体的能够看这里。以我如今的看法,只能说只要项目复杂而须要分层,那么就应该用这个模式,它让clean架构的clean更加亮眼。
这个原本就是概念,我相信你们也不肯意看,因此就简单介绍。若是想详细了解,能够戳这里。
如今谈谈本身的见解,后者是相对前者较为具体的一种符合Android的结构。在这插一个clean架构的依赖性规则:内层不能依赖外层。三者也都分别解释了是干什么用的,那么为何有分为这三者,它们又有什么联系?我是个俗人,那就应该用俗话来说,从数据层利用Repository模式让领域层感受不到数据访问层的存在,即原始数据是独立的,业务规则不绑定具体哪种数据,通俗点讲就是你要什么数据?我给你取,但你不须要知道我从哪里取的;所以领域层对数据层怎么实现的是一无所知,而领域层主要工做就是你给了我数据,那我就要用,怎么用?都是我来决定;用完以后再回调给表现层渲染UI。所以大多数的业务逻辑都在领域层,能够说是一个APP的核心。我认为这里透露着一个很重要的设计理念就是数据驱动UI,我都想给本身点个赞,哈哈。其实,到这里,你内心已经有点13数的话,能够跳到Why,由于怎么用已是具体的东西,而架构自己就是一种共识,是抽象的,从Java角度讲你能够多个类去实现这个接口。下面的使用只是我对Clean架构理解的一点代码体现。
下面的例子是从我开源库CrazyDaily中选取的,以知乎日报为例。
数据层就是从咱们的仓库(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并不是数据层的东西,而是领域层的东西,很显然,以接口进行关联,但内容独立,没错,这就是传说中的依赖倒置原则。
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)。真的感受架构愈来愈有意思了。我能够在这里处理咱们大部分的业务逻辑。
@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)
若是这都看到不懂,买块豆腐撞死算了。
其实How并非很重要,但却占了很大篇幅。
你认为Why是最重要的吗?这个问题留在心中,先来看看Why。
看见高内聚,低耦合我就头疼。说说其它吧,易于维护,这样的结构已经能说明了,易于测试也好理解,各个模块独立,来看看这:
说来惭愧,嫌麻烦,我在开源项目里并无写测试,相信我之后会加的,我也不是那种不负责任的人,献上大佬的一个关于clean的开源项目Android-CleanArchitecture。
关于clean的差很少到这里结束了,若是有什么问题,能够联系我,一块儿讨论。先喝一碗鸡汤为敬,学会平静的对待生活中的不完美之处,适应本身的情绪,了解如何让它们天然宣泄出去。说来也可笑,个人一个库MTRVA也受到了我学习架构时的影响,它是RecyclerViewAdapter的至关于Presenter层的一个东西,咱们老是免不了在Adapter中对资源或者说数据的处理,这就跟Activity一锅粥同样,它让你只关注UI逻辑。有人说,个人界面简单,啥都不用算,给我list,setAdapter,搞定。额。。。那确实不用。同理,简单的项目也并不须要什么复杂的架构,相信从头看到尾的同窗,很明显的看出clean架构的缺点,就是繁琐。架构本然就是在需求中不断演进。祝你可以搭建属于大家的架构。最后,感谢一直支持个人人!
Github:github.com/crazysunj/