基本的架构设计模式
2016-03-08 {{allComments.length}} 15470 干货分享【背景介绍】
提高生产力,是对程序员们对程序进行孜孜不倦架构设计的原因。通过不同的架构设计使程序模块化解耦以及程序内部的高聚合,使得开发人员可以在开发工程中只需关注一点或者某块的功能设计而不必关注全貌,甚至以点窥面,从某个模块的理解即可覆盖全局。同时测试设计也会因为一个更良好的架构设计而改观。在本章,笔者主要针对移动端常用的MVC、MVP、MVVM三种设计模式进行比较探讨,并结合实例,来说明三者之间的差异。
一、MVC/MVP/MVVM
MVC/MVP /MVVM是一种架构模式,它描述的是数据流向,这三者之间的差别可以由如下图,可以看到三者之前的相同点是,View均为UI层,是用户直接的交互操作入口,并负责UI交互和界面展现相关逻辑。Model层为数据对象,提供对应用程序数据的操作接口,并在数据发生变化时,发出变更通知。
图1 架构模式
那么,它们的不同点是什么呢,在MVC中,controller被动接收View的操作事件,根据事件的不同进行不同的操作,model并不直接与 controller交互,而是View通过观察者的方式,来直接与Model交互,在Android中,往往很难区分View和Controller, 所以经常会看到好几千行的Activity,非常难维护;MVP可以理解为MVC的升级版,在笔者眼中,它是第一次使客户端分层得以充分实现的一种架构模式,它的特点是,Prensenter将View和Model完全隔离,View传递事件给Presenter,而presenter直接负责View的刷新;MVVM早期应用是windows的MFC上,而近期在2015年google IO大会上,发布的新Android studio也支持了这一特性,它的基础是DATA BINDING,这一特性从理想态上来说,完美的解决了UI前端与业务逻辑层的解耦问题,哪怕是MVP也不能具有这么好的特性。
1.1 MVP设计模式实现
实现MVP并不复杂,但是重点是把握好,不要过度设计,MVP很容易导致本来很简单的代码需要大量的开发工作,写在前面,可以理解,架构的设计模式与产品体量有关,说一个极端的场景,当你的团队只有1个人,APP整体也只是一个前台展示 + 简易逻辑处理 + 数据存储 + 网络请求时,其实此时并不需要特别复杂的架构设计,而是,要用最简易便捷的方式将APP设计起来,这也遵循了产品设计之初快速产出,快速试错的目的。而当团队逐步增大、产品规模逐步提升,譬如,代码量超10W时,这时候为了团队协作、模块管理、便于测试等诉求,就不得不进行一定的架构设计或重构了。
如何讲解一个MVP的例子,还是找一个比较简单的例子切入,可能并不能说明一切端设计的场景,但是可以作为读者了解MVP的切入点,假设有一个用户数据录入的APP,具备简单功能,即用户数据录入&&简单用户数据查询功能,它的界面看起来是如下这样的:
图2 简易APP用户界面
最后的工程结构是这样的,如下图:
图3 MVP基本结构
第一步,实现数据载体Bean
public class UserBean {
private String mFirstName;
private String mLastName;
public UserBean(String firstName, String lastName) {
this. mFirstName = firstName;
this. mLastName = lastName;
}
public String getFirstName() {
return mFirstName;
}
public String getLastName() {
return mLastName;
}
}
第二步,实现Model层,model其实是对数据的CURD操作的封装,如果有网络请求或其他需要异步处理的需求,这一层通过listener与上层的presenter进行通讯
public interface IUserModel {
Boolean insert(int id, String firstName, String lastName);
Boolean update(int id, String firstName, String lastName);
void delete(int id);
UserBean query(int id);
void reset();
List<UserBean> queryAll();
}
第三步,实现presenter
public class UserPresenter {
private IUserView mUserView;
private IUserModel mUserModel;
public UserPresenter(IUserView view) {
mUserView = view;
mUserModel = new UserModel();
}
public void saveUser( int userId, String firstName, String lastName) {
mUserModel.insert(userId, firstName, lastName);
}
public void loadUser( int userId) {
UserBean user = mUserModel.query(userId);
mUserView.setFirstName(user.getFirstName());
mUserView.setLastName(user.getLastName());
}
}
第四步,实现View层
public interface IUserView {
String getFristName();
String getLastName();
void setFirstName(String firstName);
void setLastName(String lastName);
}
其中,没有标准Activity和model的实现,相信读者可以参考IUserView和IUserModel的接口就可以实现对应的view层和 model层实体了。这样就算是基于MVP设计模式,设计了一个简单的APP。但是这个APP的实现是不全的,但是对于说明MVP设计来说已经足够了。
1.2 MVVM设计模式实现
MVVM模式,并不是移动时代来临以后特有的,它起初的应用是微软的WPF(windows vista用户界面框架),所以它并不新鲜,但是,引入到了移动端,它的重要性举足轻重。简单一句话是,相对于MVP和MVC,它彻底解耦了View层和 下面的业务逻辑及数据层。MVVM的核心是”data binding”技术(数据绑定),在笔者看来,MVVM与其说是一种设计模式,笔者认为,不如说是一种前端解耦的解决方案更为妥当。
关于MVVM,在Android里是需要一个特殊的lib库支持,才能实现MVVM的架构设计模式,这个lib在2015年5月google IO发布,并已集成到了Android studio中,建议是读者可以直接参考google Android Deloper官网的Data binding部分。本篇以android端的实现为例子介绍如何一步一步实现MVVM,权当做读者的快速上手文档。仍然以上面我们已经实现了的简易 APP为例,不清楚的看第一章哟~ 构建前提是你的Android Studio升级到了1.3版本及以上(相信eclipse肯定也支持MVVM的构建,但是毕竟eclipse的开发方式逐步被Android studio替代,并且你的工程可以很容易从eclipse迁移到Android studio,鉴于此,使用studio说明MVVM的构建是OK的)
第一步,设置Android Studio,打开 Preferences -> Appearances & Behavior -> Updates -> 设置Automatically Check updates for 改为 Canary Channel。这个原因是MVVM毕竟在Android还算新的东西,并不完美,开启这个可以最快获取google发布的最新预览版,但可能会遇到 BUG。
图4 Android Studio设置
第二步,配置data binding环境,data binding是一个依赖库,他支持Android2.1 及以上版本,但需要一定的配置。具体配置为,在gradle构建文件中配置如下:
dependencies {
classpath "com.android.tools.build:gradle:1.2.3"
classpath "com.android.databinding:dataBinder:1.0-rc0"
}
在每一个想使用data binding的module中添加如下:
apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'
触发sync,等待Android studio,自动配置相关环境。这个时间有点长,建议是翻下墙。
如上配置后,就可以开始正式的开发工作了,本文所有改动仍然是实现,上一章在MVP结构下构建的APP,在上一章中,虽然初步实现了View与业务逻辑解耦,但是每种不足的是Activity仍然遗留了大量代码,譬如view内容变化、事件监听等,data binding其实就是为了解耦这部分工作而存在的,实现了data binding的APP,这些操作可以直接在xml中配置实现,并且这种模式下,是支持条件判断的。相对上一章没有列出的layout,在MVVM中,上一章中的layout XML会长成如下样子:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.baidu.msg.base.User" />
<variable name="vModel" type="com.baidu.msg.handlers.viewModel" />
</data>
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入id"
android:text="@{user.getId()}"
android:inputType="number" />
<EditText
android:id="@+id/first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="inter first name"
android:text="@{user.getFirstName()}"
android:inputType="text" />
<EditText
android:id="@+id/last"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="inter last name"
android:text="@{user.getLastName()}"
android:inputType="text" />
<Button
android:id="@+id/save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="save"
android:onClick="@{vModel.onClickButton}"
/>
<Button
android:id="@+id/load"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="load" />
</LinearLayout>
</layout>
可以见到,如上图中的xml的元素中,多了data节点,这个节点中定义的变量就与实际的view model交互,进而影响UI展现。
二、后记
如上,主要讲解了MVC/MVP/MVVM的特点及他们之间的区别,通过简单的例子说明了如何设计一个简单的MVP/MVVM架构,关于这一章,建议是不要为了架构而架构,而是选择与自己产品形态和发展时期符合的开发架构和方式。尤其是在产品早期,不是非常建议非要做成那种架构。就像百度内部的手百APP, 早期也只是简单的三层结构,并没有清晰的设计模式的概念,简单实用。无论是什么设计,都离不开低耦合、高聚合这个基本原则。