版权声明 作者:Dario Milii 译者:张天雷 本文由原作者授权翻译并发布,本文首发于移动前线公众号,未经允许禁止转载。
自从我开始进行Android应用的开发,我一直以为这项工作可以完成的更好。在我的职业生涯中,我见到过很多错误的软件设计决定,其中有一些还是我自己的。而且,这些决定导致了Android应用设计复杂度的急剧膨胀。但是,从你的错误中吸取教训并不断改进以后的做法才是非常重要的。在探索了很多应用开发的方法后,我遇到了干净架构(Clean Architecture)。在将其进行改良并引入了一些类似项目的灵感后,我把这种方法应用到了Android开发,发现该方法完全可以用于实践,值得推荐和分享。 这篇文章的目的是提供利用Clean方法进行Android应用开发的一个指南。它已在我最近为客户开发应用过程中得到成功验证。 何为干净架构 我不准备在这里解释太多细节,因为网上已经有了不少的资料(译者注:中文的资料也有一些)。下面我会给出理解Clean的关键信息。 Clean一般是指,代码以洋葱的形状依据一定的依赖规则被划分为多层:内层对于外层一无所知。这就意味着依赖只能由外向内。 其具体含义可以通过下图进行很好的展示。
干净架构使得代码可以实现:
在后面的例子中,我会详细讲解这些特征是如何达成的。我强烈推荐8thlight的一篇文章(https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html)和vimeo上的视频(https://vimeo.com/43612849)来详细了解Clean的概念。 对Android来说的意义 一般而言,你的应用可以有任意数量的层。但是,除非需要在所有的Android应用中采用企业级的业务逻辑,一般的应用至多只有三层:
实现层包含了所有框架相关的东西。框架相关的代码包含了所有不是专门用来解决目标问题的部分,例如创建activity和fragment、发送目标以及网络和数据库相关的框架代码。 接口适配层的目的就是负责连接业务逻辑和框架相关的代码。 应用中最重要的就是业务逻辑层。它负责解决你的应用所真正想解决的问题。该层不包含任何框架相关的代码,因此其代码应该可以在没有模拟器的情况下独立运行。这样,测试、开发和维护业务逻辑代码就要容易很多。而这就是干净架构的主要优势。 在核心层以上的每一层,也都负责在更低层使用模型之前将它们转换为更低层的模型。内层不能使用任何属于外部的模型类的引用;但是外层可以使用和引用内层的模型这都是因为依赖规则。这种方式会造成一定的开销,但确保了层与层之间代码的解耦合。
在文章最后,我会添加更多的相关资源来学习。现在我们已经知道了干净架构的基本概念,文章接下来将会用一些实际的代码来进行说明。下一节,我将展示了如何使用Clean来设计一个示例功能。 我所作的一些准备 我已经创建了一个框架搭建完毕的样例工程。以此作为Clean starter pack,你可以利用其中的常见的工具继续开发。该工程已发布在Github,你可以免费下载、修改和使用。 项目地址:https://github.com/dmilicic/Android-Clean-Boilerplate 开始编写一个新用例 本节将会对使用Clean方法创建一个用例所需要编写的代码进行解释。在这里,一个用例只是某个应用中被专门隔离出的部分功能。该用例可能被用户直接使用(例如,用户点击),也可能不被用户直接使用。 首先,对该方法的结构和术语进行解释。这只是我自己构建应用的方式,并非一成不变,你可以根据需求自己进行相应的变化。 结构 一个Android应用的通用结构如下:
外层 正如之前所提到的,该层是框架的具体细节所在。 UI这是所有Activity、Fragment、适配模块和其他与用户接口相关的Android代码存在的地方。 存储Interactor访问和存储数据所需要使用的接口代码。例如,它包括了ContentProvider或者DBFlow等ORM。 网络包括了Retrofit等。 中间层 负责将实现细节和业务逻辑连接起来的粘合层。 PresenterPresenter负责处理来自UI的事件(如用户点击等)和内层模块(如Interaactor等)的回调。 ConverterConverter对象负责内层模型与外层模块的相互转换工作。 内层 该层包含了绝大部分高级代码。其中所有的类都是POJO。该层中的类和对象对于Android应用相关的东西一无所知,因此可以被轻易移植到任何运行JVM的机器中。 Interactor这就是包含实际的业务逻辑代码的类。他们在后台运行,并通过回调函数将事件报告给上层。在一些项目中,他们也被称作用例。通常情况下,项目中可能包含很多小的Interactor类,用来分别解决特定的问题。这符合了单一职责原则,也比较容易对类进行理解。 Model这些就是在业务逻辑中进行处理的业务模型。 Repository该包只包含了数据库或者其他外层实现的接口。Interactor使用这些接口来访问和存储数据。这就是所谓的repository模式(https://msdn.microsoft.com/en-us/library/ff649690.aspx)。 Executor该包涵盖了使得Interactor在后台运行所需要的代码。一般情况下,用户不需要修改该包。 一个简单的例子 在该例子中,用例是:“当应用启动的时候,显示存储在数据库中的欢迎消息”。接下来,文章就分析如何编写该用例所需要用到的三个包:
其中,前两个包属于外层,而最后一个属于内层(核心层)。 显示包负责将相关内容显示到屏幕上,因而它包含了整个的MVP栈(这就意味着该包包含了属于不同层的UI包和Presenter包)。 接下来,让我们开始讨论代码。 编写新的Interactor(内层/核心层) 你可以从结构中的任何一层开始编写,但是我推荐首先从核心业务逻辑开始。你可以编写、测试,并在没有activity的情况下确保其正常工作。
该Interactor所拥有的依赖关系如下:
测试刚创建的Interactor 现在,就可以在不运行模拟器的情况下运行和测试Interactor。因此,编写一个简单的JUnit测试以确保它能够正常工作:
编写显示层 在干净架构中,显示代码属于外层。它包含了框架相关的代码,用于将UI显示给用户。这里设定使用MainActivity类来显示欢迎信息。 首先开始编写Presenter和View接口的代码。View所需要做的唯一事情就是显示欢迎信息:
MainActivity类中我们重载了onResume()方法:
启动Interactor的工作是通过resume()方法中的MainPresenter类进行的:
有关this,MainActivity的MainPresenter真正实现了Callback接口: public class MainPresenterImpl extends AbstractPresenter implements MainPresenter, WelcomingInteractor.Callback { 这也正是应用从Interactor监听消息的方法。以下就是MainPresenter中的相关方法:
public class MainActivity extends AppCompatActivity implements MainPresenter.View { 而负责显示欢迎信息的代码如下:
编写存储层 该层实现了repository的功能。所有数据库相关的代码都应该在该层中。repository模式仅仅对数据的来源进行了抽象。业务逻辑就可以不考虑数据的具体来源是数据库、服务器或者文本文件。 对于复杂的数据,可以使用ContentProvider或DBFlow等ORM工具。如果需要从网页中抓取数据,Retrofit将会是很好的工具。如果需要简单的键值存储,SharedPreference会是不错的选择。不同的工作需要根据需求来选择不同的工具。 本文中的数据库将不会是一个真正的数据库。它只是一个拥有一定仿真延迟的类:
小结 本文的示例可以通过Git仓库(https://github.com/dmilicic/Android-Clean-Boilerplate/tree/example)进行访问。类调用的关系总结如下:
|
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|