Service Oriented 的 iOS 应用架构

Intro

    前不久咱们上线了一款新的 App - Glow Baby,App 针对 0 - 12 个月大的新生宝宝,提供爸爸妈妈全面、健康、科学的育儿知识,帮助记录宝宝成长的点点滴滴。在 Glow Baby 的开发中,咱们也作了一些新的尝试 - 使用 Swift 开发,并基于 Swift 的语言特色设计了新的 iOS App 架构。数据库

    除了 Community 这部分的代码是做为一个私有的 Repo 引入,Glow Baby 基本是 100% Swift 代码。Glow Baby iOS 团队都是第一次接触 Swift,过程当中咱们踩过不少坑,遇到过不少抓狂的问题。但整体上,写 Swift 更加有趣,全部的努力最终也证实是值得的:App 运行更加流畅,代码更整洁可读性更高,咱们开发效率也大大提升。编程

    Baby App 跟 Glow 的其余几个 App 都是较为复杂的 App,由于像日记记录、本地存储、网络请求,服务器端数据的同步这些技术难点都有涉及。这些问题也都要求多线程编程。特别是数据同步,如何增量记录数据的增删改,什么时机跟服务器端进行同步。解决这些技术难题是很是有意思的工做,也是架构设计的创造性和乐趣所在。设计模式

    接下来的一系列文章咱们来看看 Baby App iOS 的应用架构。有些设计是基于 Swift 的语言特色的考虑,但并不妨碍总体的架构思路被应用在 Objective-C,甚至 Android 的 App 上。安全

MV(X)

    在介绍 Glow Baby 的应用架构以前,先来看看目前 iOS 上最基础的架构 MVC,以及为解决 MVC 的毛病而诞生的其余几个架构,如 MVVM、VIPER 等。服务器

    Cocoa 的不少技术跟架构都是基于 MVC。并且不管是文档、示例代码,仍是建立一个项目时提供的模板代码,Apple 都鼓励开发者去使用 MVC。MVC 定义了 App 里对象的角色(Model-View-Controller),以及他们之间的交互方式:网络

  • Model: 表示业务数据对象
  • View:展示数据的 UI
  • Controller:Model 跟 View 之间的粘合剂。一方面对 View 上的行为做出反应,一般会涉及到 Model 的更改;另外一方面将 Model 的改动反映到 View 上

    因为 Controller 做为粘合剂的存在,View 和 Model 只须要跟 Controller 交互,而不知道另外一方的存在。这样,View 和 Model 做为独立可复用的组件,Controller 里处理业务逻辑。听起来这样的架构很清晰直观,实际应用中,MVC 对于不是很复杂的 App 也是很是高效的。但对稍复杂些的 App,MVC 使用起来就会很是吃力。多线程

    你可能听过 MVC 也被简称为 Massive View Controller,这就是缘由所在 - View Controller 承担的职责太多:架构

  • 网络请求
  • 数据访问和存储
  • UI 的调整和组合
  • 业务逻辑
  • View 的 delegate、data source
  • 状态的维护

与单一责任准则(Single Responsibility Principle)背道而驰。过于臃肿的 View Controller 使 App 的维护成本很是高。咱们的第一个 App - Glow 其实就是这个样子,尽管咱们已经把网络请求以及数据访问和存储放到了 Model 里,但因为对象边界的定义不够清晰,大部分 View Controller 依然很臃肿,上千行的 View Controller 很常见。关于 View Controller 有个准则:若是一个 View Controller 超过了 300 行代码,那它必定作了责任范围之外的事。更不幸的是因为一些职责移交给 Model,致使 Model 也变得臃肿起来。原来惟一能够作 Unit Test 的 Model 如今测试也很困难。less

为解决 Massive View Controller 的问题,MVVM、VIPER 等架构应运而生。这里再也不详细介绍这些架构,有兴趣的读者能够自行去 Google。工具

Baby App 没有使用 MVVM 和 VIPER。由于:

  • 不够直观,提升了总体代码的复杂度,对于新入职的员工有必定学习成本
  • 要发挥 MVVM 的优点,须要有 Reactive。Reactive 增长学习成本的同时,也让调试变得更困难。
  • VIPER 虽然能平衡责任的分配,但因为引入过多对象,维护成本高。一个简单的页面也要求新增多个类和大量傻瓜代码

因此咱们结合本身的需求和 Swift 的语言特色设计了面向服务的架构(Service Oriented Architecture)。

Service Oriented Architecture

    面向服务的架构在服务器端的开发中很常见,它把业务分红了多个逻辑独立的组件。一个组件至关于一个 Service,封装了与其业务相关的功能,如 UserService 负责用户的注册、登入等,而 BabyService 有 Baby 的增长、移除、以及数据的记录等。Glow 服务器端的架构实际就是面向服务的。在 Baby App iOS 架构中引入 Service 的概念,是 App 开发过程当中迭代的结果,灵感也是来自咱们服务器端的架构。

    能够看到,Service 是对整个架构纵向逻辑切分的结果。抛开业务逻辑谈 Service 意义不大,Service 一般与数据库表的设计紧密相关。

横向的逻辑切分将 Baby App iOS 的架构自上而下切分红三个层(Layer):

  • 应用层(Application Layer)
  • 服务层(Service Layer)
  • 数据层(Data Access Layer)

    服务层和数据层把复杂的逻辑封装起来,做为 Framework 提供接口给上层调用。应用层只能调用服务层暴露出来的接口,而不能直接调用数据层。层次结构增强了可重用性和可测试性。应用层调用服务层提供的简单接口得到数据或者实行用户操做。服务层也不须要知道数据层中网络请求,服务器同步,以及数据持久化的具体实现。服务层,数据层,以及应用层都能很容易实现各自的单元测试(Unit Test)。

    Framework 是很棒的工具。把服务层和数据层打包成 Framework,不只帮助构建解耦可重用的代码,同时 App 的结构和业务逻辑也更加清晰。

应用层(Application Layer)

    应用层也能够叫展现层(Presentation Layer),负责 UI 跟 展现逻辑。从 Code 角度说,就是 UIView 跟 UIViewController 的集合。复杂的逻辑都封装到了下层,UIViewController 就变得十分轻量。在 Glow Baby 中,一个 View Controller 一般 200 至 300 行代码之间,主要负责三件事:

  1. 从 Service 得到数据(ViewModel)并展现
  2. 响应用户操做,调用相应的 Service 接口
  3. 监听 Service 层发出的消息,并执行相应操做,如更新 UI

    从 Service 获取的 ViewModel 实例并非 NSManagedObject 或者其余持久化的 model 实例,跟 MVVM 中的 ViewModel 也不同。在 Baby App 中,它只是简单的 Swift Struct,提供应用层须要的数据值。使用 Struct 的好处主要是:

  • 值类型(Value Type): 简单、容易理解,线程安全
  • 松耦合的 View Controller,减小 View Controller 之间可能的交互
  • 减小了 Statefulness 和 Mutability
  • 更高效、占用更少内存

    使用 Struct 也就意味着想要底层持久化 Model 的更改放映到 UI 上,你必须经过 Service 再抓一次数据。也许有人认为这是使用 Struct 的一个缺点。其实不是,这应该是优势。由于 Immutable 的 ViewModel ,让 View Controller 变得更加简单,你不用担忧其余地方的代码会更改你的 ViewModel 实例。调试起来也会更加方便,代码更容易理解、可读更高。WWDC 中有好几个视频都对 Struct 的使用和优点进行了详解。

    Baby App 支持 Theme,所以 Baby App 的 View Controller 还会调用 Theme 对象来设定 UI 的样式。但对 View 样式的设定都封装在了 Theme 里,因此并无增长太多代码量及 View Controller 的复杂度。

服务层(Service Layer)

    服务层定义了一系列 Service 和供给应用层使用的 ViewModel。Service 封装了 App 主要的业务逻辑,负责把底层持久化的 Model 和网络请求返回的 JSON 转换为 ViewModel,再提供给应用层使用。这样的分离即增强了 Immutablility 和 Statelessness,也让应用层中的 ViewController 更轻量,只需几行 Service calls。Service 虽然承担大部分业务逻辑,但一个 Service 一般也就 300 行左右的代码量,这得益于数据层的封装和抽象。

数据层(Data Access Layer)

数据层的做用是提供简化的数据访问接口,主要有 3 个模块:

  • 数据存储(Persistence)
  • 网络请求(Network)
  • 数据同步(Data Synchronization)

    数据存储咱们使用的是 Core Data,也能够用 Realm 或者其余数据库代替。网络请求咱们使用了 Moya 进行抽象,使 API 的设计和调用更简洁,并支持咱们 Server 自定义的错误。数据同步模块,会自动同步本地和服务器端的用户数据。

Conclusion

    在 iOS 上,MVC 因 Controller 的臃肿而遭到众人诟病。但其实 MVC 做为最基础的设计模式,展示了一个架构的精髓 - 抽象分离。这是咱们应该学习思考的,而不是盲目从其余架构模式中选择一个来代替 MVC。Glow Baby iOS 的架构从能够看做是一种 MVC。从总体看,数据层是 Model,服务层是 Controller,应用层是 View。而若是看细节的地方,应用层跟服务层提供的 ViewModel 也能够看作一个 MVC:ViewModel - UIViewController - UIView.

    设计架构也没有「最好」或者「最正确」的方式,设计自己就是一项极具创造力的工做。但架构是有好坏区别,一个好的架构应该是对团队成员最为直观,同时扩展性良好的架构。

相关文章
相关标签/搜索