完全解析Android项目架构(1) - MVC
Android开发已经日臻成熟, 以前一直困扰的项目架构问题, 也随着社区的不断努力, 从MVC中受到启发, 陆续推出MVP, MVVM等架构模型, 从而创建适合Android的开发框架. 未使用架构的项目:
- 未分离界面(UI)逻辑与业务(Business)逻辑;
- 版本迭代导致所有相关类, 不断需要修改;
- 模块高耦合低内聚, 存在隐藏Bug, 无法编码测试;
使用架构的目标就是为了解决这些问题. 所有架构都来源于早期的MVC, 即Model-View-Controller模型, 本文由近及远分析MVC, MVP, MVVM三类主流架构模式, 并解释其中的优缺点.
三个架构的分析均已完成, 参考MVC, MVP, MVVM.
MVC架构
MVC, 即Model-View-Controller, 基于页面逻辑的修改要多于业务逻辑, 分离两种逻辑减少类代码的修改.
- Model: 即数据层, 负责处理业务逻辑, 监听网络与数据库接口.
- View: 即界面(UI)层, 显示来源于Model的数据.
- Contoller: 即逻辑层, 传递用户的交互和更新Model的数据.
![](https://img.haomeiwen.com/i749674/a1f018df5d05d3b0.png)
根据MVC架构, View和Controller都会依赖于Model, View显示Model数据, Controller更新Model数据. Model从项目中分离后, 独立于UI, 允许测试. 更新Model方式的不同, 把MVC架构分为被动(Passive)模式和主动(Active)模式.
被动模式
在被动模式中, Controller是唯一操作Model的类. 基于用户的响应事件, Controller通知Model更新数据. 在Model更新后, Controller通知View更新UI, View从Model中获取数据.
![](https://img.haomeiwen.com/i749674/d0035929e57686f9.png)
主动模式
在主动模式中, Controller不是唯一操作Model的类, Model存在自更新机制. 在更新数据时, Model层使用观察者(Observer)模式通知View和其他类. View实现观察者的接口, 在Model中, 注册成为观察者, 接收通知.
![](https://img.haomeiwen.com/i749674/3c0c8c8b351fa9d3.png)
当Model层发生数据更新时, 告知全部观察者. View从Model中更新数据.
![](https://img.haomeiwen.com/i749674/70eadf66b8f7f7b1.png)
项目应用
在早期开发中, Activity(或Fragment)既是View又是Controller, 并未进行分离. 有些项目剥离出Model, 独立于平台进行测试. 在使用MVC框架时, Activity(或Fragment)代表View, 并从中剥离出不含任何的Android类(如Context等)的Controller. 对比于原始项目, MVC架构具有:
- 修改UI逻辑时, 较少修改Model;
- 修改业务逻辑时, 较少修改View.
在被动模式中, View继承基类BaseView, Controller拥有BaseView的引用, 更新数据; 在主动模式中, Model使用观察者通知View, 更新数据.
优点
MVC模式, 分离类的UI与业务职责, 增加可测试性与可扩展性. Model不引用任何Android类, 允许单元测试(Unit Test). Controller含有View的引用, 不引用Android类, 允许单元测试. View满足单一职责原则(SRP), 传递事件至Controller, 展示Model数据, 不包含业务逻辑, 允许UI测试.
缺点
View既依赖于Controller又依赖于Model. 在修改UI逻辑时, 也需要修改Model, 降低架构的灵活性. View与Model的职责部分重叠, 过于耦合, 在处理UI逻辑时, 被动模式与主动模式都会产生若干问题.
在被动模式中, Controller通知Model更新数据, 并通知View显示. 对于UI逻辑, 如果View处理, 单元测试会遗漏逻辑; 如果Model处理, 则隐式地依赖于View, 导致模块增加耦合.
// View处理UI逻辑
String docName = userModel.getName();
String docClinic = userModel.getClinic();
nameTextView.setText(docName + ", " + docClinic)
// Model处理UI逻辑
String nameAndClinic = userModel.getNameAndClinic();
nameTextView.setText(nameAndClinic);
在主动模式中, 每个UI逻辑都需要增加观察者, 保证正确更新.
MVC架构含有致命问题, 即View同时含有Controller与Model的引用; UI逻辑同时存在于View与Model之间. 这些问题导致业务逻辑与UI逻辑无法分离, 增加模块耦合, 影响重构. 这些问题在MVC的进化版MVP中逐步解决.
That's all! Enjoy it!