从.NET的宠物商店到Android MVC MVP

 

1 一些闲话

  记得刚进公司的时候,我们除了做常规的Training Project外,每天还要上课,接受各种技术培训和公司业务介绍。当时第一次知道QA和SQA的区别。Training Project时间其实比较紧张,给我们的就是一个英文的需求文档。我们要做的就是数据库设计、结构文档、用例文档、项目搭建、代码编写、单元测试,每个阶段Leader会Review。除此之外,还要E-R图、时序图、用例图。麻将虽小,五脏俱全。哦,对了,所有输出必须英文完成。最后要求项目能一键安装使用。

  不感兴趣?请直接跳到第二部分,哈哈~

  Training Project其实就是做一个购物网站,做一个WinForm,最后用上WCF。对我来说,不是什么大问题,在学校已经做过类似的了。Scott Mitchell 60多篇的ASP.NET教程被我打印出厚厚的四本小书,代码从头敲了个遍。学完后就基本熟悉ASP.NET主流控件的使用,明白数据绑定、缓存以及三层架构的作用了。那么这时候,你可以达到初级的水平了。想进一步提升自己,就要懂得一定的代码封装、自定义控件、理解Pager的生命周期等等。关于书籍,理论方面个人推荐《你必须知道的.NET》、Jeffrey Richter《深入理解 .NET》和《Windows核心编程》。博客园内也有Scott Mitchell文章的中文翻译:Scott Mitchell的ASP.NET2.0数据指南中文版索引。上个图怀念一下:

  所以我的Training Project基本就是这个风格。当然,还有鼎鼎大名的PetShop。当时的水平,也就勉强明白抽象工厂,但这个宠物商店的架构图是长这样的:

  震住菜鸟有没有?Talk is cheap, show me the code。废话少说,放码过来!代码下载下来,光是Library就近20个,菜鸟完全有点无从下手了。你说让我放码,你却退避三舍。

  扯远了,回到我的Training Project。如果光是完成这个Training Project,倒没什么。但是要求一个接一个。说一下印象中还算深刻的编码规范。

  当时接受培训的编码规范是PHILIPS C# Coding Standard,没听说过?那也没什么,微软官网的一些Internal Coding Guidelines总要了解一下吧。我们的代码被Leader要求得用上PHILIPS的规范。我记得我很认真地在每个接口和方法都加上注释,该换行换行,该加括号加括号,变量命名也合乎英文语法(呵呵~你应该见过一半英文一半拼音的命名方式吧)。最后代码Review的时候,Leader挑了一个让我无语的地方:

/// <summary>
/// Gets product info by product id.
/// </summary>
/// <param name="id">The product id</param>
public Product GetProductById(long id);

  “你看,所有的语句结束后面应该跟一个英文的“.”,你这个The product id后面没有。”

  我想肯定是我的代码注释写得很规范,他挑不出其它的毛病来。你可能还看不出来的一点,Gets必须加s,呵呵。后来,我发现这样的注释简直多余,一看方法就知道干嘛的好吗。后来写了点Objective-C,发现代码基本不用写什么注释,方法名就是一条短语,自我解释。有的人还把方法名写成一条句子,也是够离谱的。

  上面说了这么多,什么意思呢?知识储备、动手能力很重要。代码看过了也许你就忘了,敲过了才算学过,能总结出来才叫理解。

  • 设计模式是用来解决代码重用的
  • 设计模式是用来隔离变化的
  • 架构是保证软件的可用性、可扩展性、安全性

  设计模式是从编码的层面提炼出来的一种总结,而架构则着眼于全局,对系统的高层次抽象。所以,如果你还没有编写过一定量的代码(几千行、几万行或十几万行,视个人而定),哪来的代码重用、代码可扩展?设计模式基本就是前人经验的总结,有了一定的代码基础能更好地理解;架构则站在更高的维度,要求的就不单单是代码经验了,你还要懂硬件、操作系统、网络环境等等,实践和理论的结合。同时你还得了解技术的边界,能做什么,不能做什么。

2 MVC

  下面终于轮到MVC和MVP登场了,刚接触这个概念的同学可能会问:他们应该是一种设计模式吧。还真不是。那你上面还说了这么多设计模式和架构?不要紧张,这不是对比学习嘛。这个问题理清还真是需要费点力气,还好已经有人把这个问题搞明白了:为什么MVC不是一种设计模式

  从Android的角度看一下MVC:

Model

  模型层就是一些基础数据源,通常是数据库SQLite、网络请求的JSON、本地XML或Java对象数据。它代表了一些实体类,用来描述你的业务逻辑怎么进行组合,同时也为数据定义业务规则。

Controller

  控制器是与应用程序相关联的动作集合,它负责处理待响应的请求。它通过界面响应用户输入,通过模型层处理数据,最后返回结果给界面。控制器扮演着模型和界面的粘合剂角色。

View

  界面就是各种UI组件(XML布局或Java自定义控件对象)。它只负责展示数据,同时接收控制器传过来的结果。

  所以在Android中,activity界面就是View,本地数据或网络数据就是Model,至于Controller嘛,看项目代码怎么组织了。一般来说,activity可以认为是Controller,一方面它负责视图的呈现,一方面控制业务逻辑(先从本地取缓存数据,再从服务端刷新;等等)并处理相关数据。做得好一点,无非再封装一层BusinessLogic,activity再去调用这个BusinessLogic,从而减轻activity的代码负担。但也逃离不了BusinessLogic+activity就是Controller的范畴,因为两者之间存在直接依赖,而且是依赖于具体实现。

  上图模拟了界面可能被用户点击,通过事件传递到控制器,接着控制器发起一个网络请求,响应结果经过转换到了模型层,最后控制器取得模型层的数据并通知界面进行刷新。Android用到MVC的具体实现很多,如ListView,Adapter就是典型的Controller,它在数据变化的时候,就是这样通知界面的:

adapter.notifyDataSetChanged();

  让我们简化上面的图示:

  当然,这是一种理想状态。在Android中,View和Model也有关联的,所以更接近的图示应该是这样的:

3 MVP

  MVP(Model-View-Presenter),你可以把它看作MVC的一个变种,用来隔离UI、UI逻辑和业务逻辑、业务数据。

  Presenter代表界面负责处理UI事件,它也需要通过界面来获得用户的输入,然后通过模型层处理数据,再返回结果给界面。跟View和Controller不同的地方在于:View和Presenter利用了接口机制,所以他们完全解耦。所以MVP比MVC更利于后期的扩展和维护,是因为它针对了接口编程。看看上面的PetShop架构图,是不是看到了众多的Interface?了解我放那张图的用心良苦了吧,面向接口编程和合理的层次划分。看一个简单的C#例子。

  接口定义:

public interface IProduct
{
/// <summary>
/// 获取所有的产品信息
/// </summary>
/// <returns>产品信息集合</returns>
List<Product> GetAllProducts(); /// <summary>
/// 通过产品编号获取产品信息
/// </summary>
/// <param name="productId">产品编号</param>
/// <returns>产品实体具体信息</returns>
Product GetProductById(long productId);
}

  从SQL Server数据库获取数据

public class SQLServerProvider : IProduct
{
public List<Product> GetAllProducts()
{
// TODO
} public Product GetProductById(long productId)
{
// TODO
}
}

  从Oracle数据获取数据

public class OracleProvider : IProduct
{
public List<Product> GetAllProducts()
{
// TODO
} public Product GetProductById(long productId)
{
// TODO
}
}

  使用

class Program
{
static void Main(string[] args)
{
IProduct productProvider= new SQLServerProvider();
productProvider.getAllProducts(); // 或者
IProduct productProvider= new OraclerProvider();
productProvider.getAllProducts();
}
}

  只要接口不变,以后你想从SQLite、DB2获取数据,只需要再写个类实现IProduct接口就行了,完全不需要修改原有的类,然后在实例化的时候换一下new的对象。是不是有点开闭的意味?对扩展开放,对修改关闭。这就是设计模式中的开闭原则(OCP:Open Closed Principle)。利用接口编程,也方便了后期进行单元测试。

  回到我们的Presenter,总结一下MVP的关键点:

  • 用户与View进行交互
  • View和Presenter是一对一关系
  • View持有Presenter的引用,但View对Model没有引用

4 MVP在Android中的实现

  有人实现了一个demo,我们来学习一下吧 。以下是类图:

  四个接口:OnLoginFihishedListener, LoginPresenter, LoginInteractor, LoginView,两个实现类:LoginPresenterImpl和LoginInteractorImpl,一个登录界面LoginActivity。看起来有点费劲?我再把它抽象一下:

  代码核心如下,注释中的1->2->3->4->5就是具体的调用流程

public class LoginActivity extends Activity implements LoginView, View.OnClickListener {
private LoginPresenter presenter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
presenter = new LoginPresenterImpl(this);
} @Override
public void onClick(View v) {
// 1、调用LoginPresenterImpl进行校验
presenter.validateCredentials(username.getText().toString(), password.getText().toString());
} @Override
public void navigateToHome() {
// 5、回调结果,LoginActivity作跳转
startActivity(new Intent(this, MainActivity.class));
finish();
}
}
public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
private LoginView loginView;
private LoginInteractor loginInteractor; public LoginPresenterImpl(LoginView loginView) {
this.loginView = loginView;
this.loginInteractor = new LoginInteractorImpl();
} @Override
public void validateCredentials(String username, String password) {
// 回调,通知LoginActivity,显示加载中提示
if (loginView != null) {
loginView.showProgress();
}
// 2、开始调用LoginInteractorImpl中的方法
loginInteractor.login(username, password, this);
} @Override
public void onSuccess() {
// 4、回调,通知LoginActivity
if (loginView != null) {
loginView.navigateToHome();
}
}
}
public class LoginInteractorImpl implements LoginInteractor {
@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener) {
// 3、TODO,登录逻辑。成功后回调给上层调用者
listener.onSuccess();
}
}

  好了,就这样。画图太累了,如对你有帮助,就推荐一下吧。

Android MVC MVP的更多相关文章

  1. android MVC && MVP && MVVM分析和对比

    相关:http://www.cnblogs.com/wytiger/p/5305087.html 出处http://blog.csdn.net/self_study,对技术感兴趣的同鞋加群544645 ...

  2. [转载]Android MVC,MVP和MVVM 思想&例子

    在Android开发中,常采用 MVC(Model-View-Controller)或者MVP(Model-View-Presenter) 等框架模式.设计如图   mvc mvp 可以看出,在 MV ...

  3. 从.NET的宠物商店到Android MVC MVP

    1 一些闲话 记得刚进公司的时候,我们除了做常规的Training Project外,每天还要上课,接受各种技术培训和公司业务介绍.当时第一次知道QA和SQA的区别.Training Project时 ...

  4. Android MVC,MVP,MVVM模式入门——重构登陆注册功能

    一  MVC模式: M:model,业务逻辑 V:view,对应布局文件 C:Controllor,对应Activity 项目框架: 代码部分: layout文件(适用于MVC和MVP两个Demo): ...

  5. Android MVC MVP MVVM (三)

    MVVM Model-View-ViewModel的简写 在MVP基础上实现数据视图的DataBinding,数据变化,视图自动变化,反之也成立. DataBinding 启用DataBinding ...

  6. Android MVC MVP MVVM (二)

    MVP模型 View主要是Activity,Fragment MVP和MVC的差别 1.Model和View不再直接通信,通过中间层Presenter来实现. 2.Activity的功能被简化,不再充 ...

  7. Android MVC MVP MVVM (一)

    示例效果 一共三个控件,EditText,Button,TextView 成功显示账号信息,查询失败显示错误信息. <?xml version="1.0" encoding= ...

  8. Android App的设计架构:MVC,MVP,MVVM与架构经验谈

    相关:http://www.cnblogs.com/wytiger/p/5996876.html 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开发中,很多人经常会头疼于 ...

  9. Android App的设计架构:MVC,MVP,MVVM与架构AAAAA

    1. 架构设计的目的1.1 通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.1.2 这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点,提高程序开发的效率,并且更容易进行后续 ...

随机推荐

  1. sort 使用 tab键 作为 分隔符_人生如梦_百度空间

    sort 使用 tab键 作为 分隔符_人生如梦_百度空间 sort 使用 tab键 作为 分隔符 For some reason "\t" doesn't work right, ...

  2. birt报表报错, There is no report design object available.org.eclipse.birt.report.exception.ViewerExcepti

    报错信息例如以下: - There is no report design object available. org.eclipse.birt.report.exception.ViewerExce ...

  3. Android常用开源项目

    Android开源项目第一篇——个性化控件(View)篇   包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Progre ...

  4. OCP读书笔记(10) - 使用闪回技术I

    使用闪回技术查询数据 闪回查询:就是查询表在过去某个时间点的数据,所用到的技术就是undo数据 SQL> conn scott/tiger 创建测试表 SQL> create table ...

  5. hdu4280(最大流)

    传送门:Island Transport 题意:有N个岛屿 M条无向路 每个路有一最大允许的客流量,求从最西的那个岛屿最多能运用多少乘客到最东的那个岛屿. 分析:无向图正反都加弧,权值一样,这题点多, ...

  6. 用 C++ 标准模板库(STL)的 vector 实现二叉搜索树(BST)

    本文由 Justme0翻译自 Code Project 转载请参见文章末尾处的要求. 介绍 众所周知,要建一棵树,我们需要关注它的内存分配与释放.为了避开这个问题,我打算用C++ STL(vector ...

  7. H3C SecPath F100-C 防火墙配置说明

    最近的工作需要,将H3C SecPath F100-C天津联通的房间防火墙配置: 网络拓扑例如,下面的: 进入系统管理界面: 默认登陆地址:192.168.0.1 截图由于涉及公司信息就没有上传.大家 ...

  8. Creating Contextual Menus创建上下文菜单

    A contextual menu offers actions that affect a specific item or context frame in the UI. You can pro ...

  9. SE 2014年4月24日

    如图配置交换网络 由于网络规模较小,企业将网络划分为了接入层和核心层两层 核心层设备(Sw1 Sw2 Sw3)作为用户的网关设备,提供三层转发功能 接入层设备(SW4 SW5)连接用户,分别划分三vl ...

  10. Objective-c 中的算术函数和常数的表示

    常数 常数名 说明 M_PI 圆周率(=π) M_PI_2 圆周率的1/2(=π/2) M_PI_4 圆周率的1/4(=π/4) M_1_PI =1/π M_2_PI =2/π M_E =e M_LO ...