没有最好的架构,只有适合的架构。
起源
由Robert C.Martin提出的Clean Architecture ,与平台无关的抽象架构。可以了解作者的原文https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html,译文:http://www.jdon.com/artichect/the-clean-architecture.html。
他梳理了软件中不同层之间的关系,提出了一个由外向内,单向依赖架构。
依赖规则Dependency Rule
上图中同心圆代表各种不同领域的软件。一般来说,越深入代表你的软件层次越高。外圆是战术实现机制,内圆的是战略核心策略。
使此体系架构能够工作的关键是依赖规则。这条规则规定源代码只能向内依赖,在最里面的部分对外面一点都不知道,也就是内部不依赖外部,而外部依赖内部(外部需要内部的具体实现策略)。这种依赖包含代码名称,或类的函数,变量或任何其他命名软件实体。
同样,在外面圈中使用的数据格式不应被内圈中使用,特别是如果这些数据格式是由外面一圈的框架生成的。我们不希望任何外圆的东西会影响内圈层。
越靠近内层,越变得抽象,越接近设计的核心。越靠近外层,越和具体的平台和实现技术相关。内层的部分完全不知道外层的存在和实现方式,代码只能从外层向内层引用,目的是为了实现层与层之间的隔离。将不同抽象程度的层进行隔离,做到了把业务规则和具体实现分离开。
Enterprise Business Rules
代表了这个软件项目的业务规则。由数据实体体现,是一些可以在不同的程序应用之间共享的数据结构。
Application Business Rules
代表了本应用所使用的一些业务规则。封装和实现了用到的业务功能,会将各种实体的数据结构转为在用例中传递的实体类,但是和具体的数据库技术或者UI无关。
在这个层的软件包含应用指定的业务规则,它封装和实现系统的所有用例,这些用例会混合各种来自实体的各种数据流程,并且指导这些实体使用企业规则来完成用例的功能目标。 我们并不期望改变这层会影响实体层. 我们也不期望这层被更外部如数据库 UI或普通框架影响,这层也是因为关注而外部分离的。 我们期望应用层面的技术操作都不能影响用例层,如果需求中用例发生改变,这个层的代码才会发生改变。
Interface Adapters
接口适配层。将用例的规则和具体的实现技术进行抽象地对接,将用例中用到的实体类转为供数据库存储的格式或者供View展示的格式。类似于MVVM中把Model的数据传递给ViewModel供View显示。
右下角表示了接口适配层中不同模块间的通信方式。不同的模块在业务用例中产生关联和数据传递。Input、Output就是Use Case提供给外层的数据流动接口。
Frameworks & Drivers
库和驱动层,代表了选用的各种具体的实现技术,例如持久层使用SQLite还是Core Data,网络层使用NSURLSession、NSURLConnection还是AFNetworking等。
总结
可以看到,Clean Architecture里已经出现了Use Case、Interactor、Presenter等概念,它为VIPER的工程实现提供了设计思想,VIPER将它的设计转化成了具体的实现。VIPER里的各部分正是存在着由外向内的依赖,从外向内表现为:View -> Presenter -> Interactor -> Entity
,Wireframe
严格来说也是一类特殊的Use Case,用于不同模块之间通信,连接了不同的Presenter
。
重要的是,VIPER架构是根据由外向内的依赖关系来设计的。从此VIPER诞生而来。
VIPER架构图
VIPER的全称是 View - Interactor-Presenter-Entity-Router。
各部分的职责:
View
- 提供完整的视图,负责视图的组合、布局、更新
- 向Presenter提供更新视图的接口
- 将View相关的事件发送给Presenter
根据展示器的要求显示界面,并将用户输入反馈给展示器。
Presenter
- 接收并处理来自View的事件
- 向Interactor请求调用业务逻辑
- 向Interactor提供View中的数据
- 接收并处理来自Interactor的数据回调事件
- 通知View进行更新操作
- 通过Router跳转到其他View
包含为显示(从交互器接受的内容)做的准备工作的相关视图逻辑,并对用户输入进行反馈(从交互器获取新数据)
Router/Wireframe
- 提供View之间的跳转功能,减少了模块间的耦合
- 初始化VIPER的各个模块
包含用来描述屏幕显示和显示顺序的导航逻辑。
Interactor
- 维护主要的业务逻辑功能,向Presenter提供现有的业务用例
- 维护、获取、更新Entity
- 当有业务相关的事件发生时,处理事件,并通知Presenter
包含由用例指定的业务逻辑。即关于数据和网络请求的业务逻辑,例如创建一个实体(数据),或者从服务器中获取一些数据。为了实现这些功能,需要使用服务、管理器,但是他们并不被认为是 VIPER 架构内的模块,而是外部依赖。
Entity
- 包含交互器要使用的基本模型对象。
普通的数据对象,不属于数据访问层次,因为数据访问属于交互器的职责
VIPER是在有意的弱化Controller的作用,而仅仅是把Controller当成View。
VIPER架构实现
git clone https://woodjobber@bitbucket.org/woodjobber/xaixsnode.git