Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2188277
  • 博文数量: 866
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10638
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/landuochong

文章分类

全部博文(866)

文章存档

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(70)

2011年(103)

2010年(360)

2009年(283)

2008年(22)

分类: Android平台

2018-01-29 14:28:27

传送门

MVC

结构简介



实例分析

Controller控制器式
点击(此处)折叠或打开
  1. public class MainActivity extends ActionBarActivity implements OnWeatherListener, View.OnClickListener {

  2.  
  3. private WeatherModel weatherModel;
  4. private Dialog loadingDialog;
  5. private EditText cityNOInput;
  6. private TextView city;
  7. private TextView cityNO;
  8. private TextView temp;
  9. private TextView wd;
  10. private TextView ws;
  11. private TextView sd;
  12. private TextView wse;
  13. private TextView time;
  14. private TextView njd;

  15.  
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20. weatherModel = new WeatherModelImpl();
  21. initView();
  22. }

  23.  
  24. /**
  25. * 初始化View
  26. */
  27. private void initView() {
  28. cityNOInput = findView(R.id.et_city_no);
  29. city = findView(R.id.tv_city);
  30. cityNO = findView(R.id.tv_city_no);
  31. temp = findView(R.id.tv_temp);
  32. wd = findView(R.id.tv_WD);
  33. ws = findView(R.id.tv_WS);
  34. sd = findView(R.id.tv_SD);
  35. wse = findView(R.id.tv_WSE);
  36. time = findView(R.id.tv_time);
  37. njd = findView(R.id.tv_njd);
  38. findView(R.id.btn_go).setOnClickListener(this);

  39.  
  40. loadingDialog = new ProgressDialog(this);
  41. loadingDialog.setTitle(加载天气中...);
  42. }

  43.  
  44. /**
  45. * 显示结果
  46. *
  47. * @param weather
  48. */
  49. public void displayResult(Weather weather) {
  50. WeatherInfo weatherInfo = weather.getWeatherinfo();
  51. city.setText(weatherInfo.getCity());
  52. cityNO.setText(weatherInfo.getCityid());
  53. temp.setText(weatherInfo.getTemp());
  54. wd.setText(weatherInfo.getWD());
  55. ws.setText(weatherInfo.getWS());
  56. sd.setText(weatherInfo.getSD());
  57. wse.setText(weatherInfo.getWSE());
  58. time.setText(weatherInfo.getTime());
  59. njd.setText(weatherInfo.getNjd());
  60. }

  61.  
  62. /**
  63. * 隐藏进度对话框
  64. */
  65. public void hideLoadingDialog() {
  66. loadingDialog.dismiss();
  67. }

  68.  

  69.  
  70. @Override
  71. public void onClick(View v) {
  72. switch (v.getId()) {
  73. case R.id.btn_go:
  74. loadingDialog.show();
  75. weatherModel.getWeatherData(cityNOInput.getText().toString().trim(), this);
  76. break;
  77. }
  78. }

  79.  
  80. @Override
  81. public void onSuccess(Weather weather) {
  82. hideLoadingDialog();
  83. displayResult(weather);
  84. }

  85.  
  86. @Override
  87. public void onError() {
  88. hideLoadingDialog();
  89. Toast.makeText(this, 获取天气信息失败, Toast.LENGTH_SHORT).show();
  90. }

  91.  
  92. private T findView(int id) {
  93. return (T) findViewById(id);
  94. }

  95.  
  96. }
Model模型
点击(此处)折叠或打开
  1. public interface WeatherModel {
  2. void getWeatherData(String cityNumber, OnWeatherListener listener);
  3. }

点击(此处)折叠或打开

  1. public class WeatherModelImpl implements WeatherModel {

  2.  
  3. @Override
  4. public void getWeatherData(String cityNumber, final OnWeatherListener listener) {

  5.  
  6. /*数据层操作*/
  7. VolleyRequest.newInstance().newGsonRequest(http://www.weather.com.cn/data/sk/ + cityNumber + .html,
  8. Weather.class, new Response.Listener() {
  9. @Override
  10. public void onResponse(Weather weather) {
  11. if (weather != null) {
  12. listener.onSuccess(weather);
  13. } else {
  14. listener.onError();
  15. }
  16. }
  17. }, new Response.ErrorListener() {
  18. @Override
  19. public void onErrorResponse(VolleyError error) {
  20. listener.onError();
  21. }
  22. });
  23. }
  24.    
  25.   public OnWeatherListener{
  26.             void onSuccess(Weather weather);
  27.             void onError();
  28. }
  29. }

总结
  • 扩展性好、维护性、模块职责明确
  • 耦合性低(解耦)、V和M非真正意义上的分离
什么时候适合使用MVC设计模式?
当一个小的项目且无需频繁修改需求就不用MVC框架来设计了,那样反而觉得代码过度设计,代码臃肿。一般在大的项目中,且业务逻辑处理复杂,页面显示比较多,需要模块化设计的项目使用MVC就有足够的优势了。

MVP

结构简介

 

为什么使用MVP模式

在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由Presenter处理).
另外,在MVP模式中,处理复杂逻辑的Presenter是通过interface与View(Activity)进行交互的,我们可以通过自定义类实现这个interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试的时间。

实例分析

MVP模式
View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。
官方模式图
案例
我们将上边的例子改成MVP模式 
WeatherModel不变 

点击(此处)折叠或打开

  1. public interface WeatherModel {
  2.   
  3.         void getWeatherData(String cityNumber, OnWeatherListener listener);
  4.  
  5. }
WeatherPresenter:只在view和model之间传递信息, 控制view的显示刷新等操作,不要做view的直接操作
     我们需要根据业务需要定义接口,把view和model之间的关联进行描述
点击(此处)折叠或打开
  1. public interface WeatherPresenter{
  2.     void getWeather(String cityNumber, OnWeatherListener listener);
  3. }

WeatherView 所有跟view相关的操作都应该在这个子类里完成,这个类根据业务需要做了接口定义,抽出这一层的目的就是做单元测试的时候可以不创建具体的View

点击(此处)折叠或打开

  1. public interface WeatherView{
  2. void showProgress();
  3. void hideProgress();

  4.  
  5.   void onSuccess(Weather weather);
  6.   void onError();
  7. }

WeatherPresenterImpl
点击(此处)折叠或打开
  1. public class WeatherPresenterImpl implements WeatherPresenter,WeatherModelImpl.OnWeatherListener{
  2. private static final String TAG = "WeatherPresenterImpl";
  3. private WeatherModel mModel;
  4. private WeatherView mView;

  5.  
  6. public WeatherPresenterImpl(WeatherView view) {
  7. this.mTopicModel = newWeatherModelImpl();
  8. this.mView = view;
  9. }

  10.  
  11. @Override
  12. public void getWeather(String cityNumber, OnWeatherListener listener){
  13.     mView.showProgress();
  14. mModel.getWeatherData(context, this);
  15. }

  16.  
  17. @Override
  18. public void onSuccess(Weather weather) {
  19. mView.hideProgress();
  20. mView.onSuccess(weather);
  21. }

  22.  
  23. @Override
  24. public void onError() {
  25. mView.hideProgress();
  26. mView.onError();
  27. }
  28. }

MainActivity :
点击(此处)折叠或打开
  1. public class MainActivity extends ActionBarActivity implements OnWeatherListener, View.OnClickListener, WeatherView {

  2.  
  3. private WeatherPresenter presenter;
  4. private Dialog loadingDialog;
  5. private EditText cityNOInput;
  6. private TextView city;
  7. private TextView cityNO;
  8. private TextView temp;
  9. private TextView wd;
  10. private TextView ws;
  11. private TextView sd;
  12. private TextView wse;
  13. private TextView time;
  14. private TextView njd;

  15.  
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20. presenter = new WeatherPresenterImpl();
  21. initView();
  22. }

  23.  
  24. /**
  25. * 初始化View
  26. */
  27. private void initView() {
  28. cityNOInput = findView(R.id.et_city_no);
  29. city = findView(R.id.tv_city);
  30. cityNO = findView(R.id.tv_city_no);
  31. temp = findView(R.id.tv_temp);
  32. wd = findView(R.id.tv_WD);
  33. ws = findView(R.id.tv_WS);
  34. sd = findView(R.id.tv_SD);
  35. wse = findView(R.id.tv_WSE);
  36. time = findView(R.id.tv_time);
  37. njd = findView(R.id.tv_njd);
  38. findView(R.id.btn_go).setOnClickListener(this);

  39.  
  40. loadingDialog = new ProgressDialog(this);
  41. loadingDialog.setTitle(加载天气中...);
  42. }

  43.  
  44. /**
  45. * 显示结果
  46. *
  47. * @param weather
  48. */
  49. public void displayResult(Weather weather) {
  50. WeatherInfo weatherInfo = weather.getWeatherinfo();
  51. city.setText(weatherInfo.getCity());
  52. cityNO.setText(weatherInfo.getCityid());
  53. temp.setText(weatherInfo.getTemp());
  54. wd.setText(weatherInfo.getWD());
  55. ws.setText(weatherInfo.getWS());
  56. sd.setText(weatherInfo.getSD());
  57. wse.setText(weatherInfo.getWSE());
  58. time.setText(weatherInfo.getTime());
  59. njd.setText(weatherInfo.getNjd());
  60. }

  61.  
  62. /**
  63. * 隐藏进度对话框
  64. */
  65. public void hideProgress() {
  66. loadingDialog.dismiss();
  67. }

  68.  
  69.   public void showProgress(){
  70.                 loadingDialog.show();
  71. }

  72.  
  73. @Override
  74. public void onClick(View v) {
  75. switch (v.getId()) {
  76. case R.id.btn_go:
  77. presenter.getWeather(cityNOInput.getText().toString().trim(), this);
  78. break;
  79. }
  80. }

  81.  
  82. @Override
  83. public void onSuccess(Weather weather) {
  84. displayResult(weather);
  85. }

  86.  
  87. @Override
  88. public void onError() {
  89. hideLoadingDialog();
  90. Toast.makeText(this, 获取天气信息失败, Toast.LENGTH_SHORT).show();
  91. }

  92.  
  93. private T findView(int id) {
  94. return (T) findViewById(id);
  95. }
  96. }

MVP与MVC的异同
MVC模式与MVP模式都作为用来分离UI层与业务层的一种开发模式被应用了很多年。在我们选择一种开发模式时,首先需要了解一下这种模式的利弊:
无论MVC或是MVP模式都不可避免地存如下弊端,这就导致了这两种开发模式也许并不是很小型应用。
  • 额外的代码复杂度和学习成本
但比起他们的优点,这点弊端基本可以忽略了:
  • 降低耦合度
  • 模块职责划分明显
  • 利于测试驱动开发
  • 代码复用
  • 隐藏数据
  • 代码灵活性
对于MVP与MVC这两种模式,它们之间也有很大的差异。以下是这两种模式之间最关键的差异: 
MVP模式:
  • View不直接与Model交互,而是通过与Presenter交互来与Model间接交互
  • Presenter与View的交互是通过接口来进行的,更有利于添加单元测试
  • 通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑
MVC模式:
  • View可以与Model直接交互
  • Controller是基于行为的,并且可以被多个View共享
  • 可以负责决定显示哪个View


阅读(1561) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册