MVC设计思想
Posted Java面试集合
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MVC设计思想相关的知识,希望对你有一定的参考价值。
1. 为什么需要MVC ?
软件中最核心的,最基本的东西是什么?
答:是的,是数据。我们写的所有代码,都是围绕数据的。
围绕着数据的产生、修改等变化,出现了业务逻辑。
围绕着数据的显示,出现了不同的界面技术。没有很好设计的代码,常常就会出现数据层(持久层)和业务逻辑层还有界面代码耦合的情况。ORM等框架,解耦合了业务逻辑和数据之间的耦合,业务逻辑不再关心底层数据如何存储和读取。所有数据呈现给业务逻辑层的就是一个个的对象。而MVC, MVP, MMVM用来解决业务逻辑和视图之间的耦合。
2. MVC
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。其中M层处理数据,业务逻辑等;V层处理界面的显示结果;C层起到桥梁的作用,来控制V层和M层通信以此来达到分离视图显示View和业务逻辑层Model。MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
说了这么多,听着感觉很抽象,废话不多说,我们来看看MVC在android开发中是怎么应用的吧!
• Model层:适合做一些业务逻辑处理,比如数据库存取操作,网络操作,复杂的算法,耗时的任务等都在model层处理。
Model在values目录下通过xml文件格式生成,也可以通过硬编码的方式直接Java代码生成。View和Model是通过桥梁Adapter来连接起来。
• View层:应用层中处理数据显示的部分,XML布局可以视为V层,显示Model层的数据结果。 View是软件应用传送给用户的一个反馈结果。它代表软件应用中的图形展示、声音播放、触觉反馈等职责。视图的根节点是应用程序的自身窗口。比如,视频播放器中可能包含当前播放的画面,这个画面就是一个视图。另一个视图组件可能是该视频的文字标题。再一个就是一些播放按键,比如:Stop、Start、Pause等按钮。
总而言之,MVC框架如下:
View 是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。
Controller 是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,想用用户出发的相关事件,交给Model处理。
Model 应用程序的主体部分,所有的业务逻辑都应该写在该层。
-----------------------------------------------MVC典型例子的实现ListView-----------------------------------------
Android中最典型MVC是ListView,要显示的数据是Model,界面中的ListView是View,控制数据怎样在ListView中显示是Controller,这里可以理解Activity是Controller。
• 通过硬编码的方式直接Java代码生成方式,这里直接在注释讲解:
[java] view plain copy
public class ArrayAdapterActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView listView = new ListView(this);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData());
listView.setAdapter(adapter);
setContentView(listView);
// 点击事件,Controller负责
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// position是从0开始的,获取点击item的内容
Toast.makeText(ArrayAdapterActivity.this, getData().get(position), Toast.LENGTH_SHORT).show();
}
});
}
// 要显示的数据Model,通过硬编码的方式直接Java代码生成
private List<String> getData() {
List<String> data = new ArrayList<String>();
data.add("a");
data.add("b");
data.add("c");
data.add("d");
return data;
}
}
• 视图View和模型Model取资源文件方式:
先在res/layout文件夹下创建文件activity_arrayadapter.xml,可以看出只包含一个ListView,即视图View
[java] view plain copy
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6 <ListView
7 android:id="@+id/listview"
8 android:layout_width="fill_parent"
9 android:layout_height="fill_parent"
10 android:drawSelectorOnTop="false" />
11 </LinearLayout>
在res/values文件夹下的strings.xml添加一个字符数组,及模型Model
[html] view plain copy
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3 <string-array name="good">
4 <item>a</item>
5 <item>b</item>
6 <item>c</item>
7 <item>d</item>
8 </string-array>
9 </resources>
Activity代码,在注释中讲解MVC模型使用:
[java] view plain copy
1 public class ArrayAdapterActivity2 extends Activity {
2 @Override
3 protected void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 setContentView(R.layout.activity_arrayadapter);
6
7 ListView listView = (ListView) findViewById(R.id.listview);
8
9 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData());
10
11 listView.setAdapter(adapter);
12 // 点击事件,Controller负责
13 listView.setOnItemClickListener(new OnItemClickListener() {
14 @Override
15 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
16 // position是从0开始的,获取点击item的内容
17 Toast.makeText(ArrayAdapterActivity2.this, getData().get(position), Toast.LENGTH_SHORT).show();
18 }
19 });
20 }
21 // 要显示的数据Model,Model在values目录下通过xml文件格式生成
22 private List<String> getData() {
23 List<String> data = new ArrayList<String>();
24 Resources res =getResources();
25 // 取xml文件格式的字符数组
26 String[] good=res.getStringArray(R.array.good);
27 for(int i=0;i<good.length;i++){
28 data.add(good[i]);
29 }
30 return data;
31 }
32 }
Android的MVC模式要在项目中慢慢理解,这样才能理解透彻并活学活用。
-----------------------------------------------MVC典型例子之获取天气预报数据-----------------------------------------
先上一个界面图:
Controller控制器:
[java] view plain copy
1 package com.xjp.androidmvcdemo.controller;
2
3 import android.app.Dialog;
4 import android.app.ProgressDialog;
5 import android.os.Bundle;
6 import android.support.v7.app.ActionBarActivity;
7 import android.view.View;
8 import android.widget.EditText;
9 import android.widget.TextView;
10 import android.widget.Toast;
11
12 import com.xjp.androidmvcdemo.R;
13 import com.xjp.androidmvcdemo.entity.Weather;
14 import com.xjp.androidmvcdemo.entity.WeatherInfo;
15 import com.xjp.androidmvcdemo.model.OnWeatherListener;
16 import com.xjp.androidmvcdemo.model.WeatherModel;
17 import com.xjp.androidmvcdemo.model.WeatherModelImpl;
18
19
20 public class MainActivity extends ActionBarActivity implements OnWeatherListener, View.OnClickListener {
21
22 private WeatherModel weatherModel;
23 private Dialog loadingDialog;
24 private EditText cityNOInput;
25 private TextView city;
26 private TextView cityNO;
27 private TextView temp;
28 private TextView wd;
29 private TextView ws;
30 private TextView sd;
31 private TextView wse;
32 private TextView time;
33 private TextView njd;
34
35 @Override
36 protected void onCreate(Bundle savedInstanceState) {
37 super.onCreate(savedInstanceState);
38 setContentView(R.layout.activity_main);
39 weatherModel = new WeatherModelImpl();
40 initView();
41 }
42
43 /**
44 * 初始化View
45 */
46 private void initView() {
47 cityNOInput = findView(R.id.et_city_no);
48 city = findView(R.id.tv_city);
49 cityNO = findView(R.id.tv_city_no);
50 temp = findView(R.id.tv_temp);
51 wd = findView(R.id.tv_WD);
52 ws = findView(R.id.tv_WS);
53 sd = findView(R.id.tv_SD);
54 wse = findView(R.id.tv_WSE);
55 time = findView(R.id.tv_time);
56 njd = findView(R.id.tv_njd);
57 findView(R.id.btn_go).setOnClickListener(this);
58
59 loadingDialog = new ProgressDialog(this);
60 loadingDialog.setTitle(加载天气中...);
61
62
63 }
64
65 /**
66 * 显示结果
67 *
68 * @param weather
69 */
70 public void displayResult(Weather weather) {
71 WeatherInfo weatherInfo = weather.getWeatherinfo();
72 city.setText(weatherInfo.getCity());
73 cityNO.setText(weatherInfo.getCityid());
74 temp.setText(weatherInfo.getTemp());
75 wd.setText(weatherInfo.getWD());
76 ws.setText(weatherInfo.getWS());
77 sd.setText(weatherInfo.getSD());
78 wse.setText(weatherInfo.getWSE());
79 time.setText(weatherInfo.getTime());
80 njd.setText(weatherInfo.getNjd());
81 }
82
83 /**
84 * 隐藏进度对话框
85 */
86 public void hideLoadingDialog() {
87 loadingDialog.dismiss();
88 }
89
90
91 @Override
92 public void onClick(View v) {
93 switch (v.getId()) {
94 case R.id.btn_go:
95 loadingDialog.show();
96 weatherModel.getWeather(cityNOInput.getText().toString().trim(), this);
97 break;
98 }
99 }
100
101 @Override
102 public void onSuccess(Weather weather) {
103 hideLoadingDialog();
104 displayResult(weather);
105 }
106
107 @Override
108 public void onError() {
109 hideLoadingDialog();
110 Toast.makeText(this, 获取天气信息失败, Toast.LENGTH_SHORT).show();
111 }
112
113 private <t extends="" view=""> T findView(int id) {
114 return (T) findViewById(id);
115 }
116
117 }
Model模型
来看看WeatherModelImpl代码实现:
[java] view plain copy
1 package com.xjp.androidmvcdemo.model;
2
3 /**
4 * Description:请求网络数据接口
5 * User: xjp
6 * Date: 2015/6/3
7 * Time: 15:40
8 */
9
10 public interface WeatherModel {
11 void getWeather(String cityNumber, OnWeatherListener listener);
12 }
13
14 ................
15
16
17 package com.xjp.androidmvcdemo.model;
18
19 import com.android.volley.Response;
20 import com.android.volley.VolleyError;
21 import com.xjp.androidmvcdemo.entity.Weather;
22 import com.xjp.androidmvcdemo.volley.VolleyRequest;
23
24 /**
25 * Description:从网络获取天气信息接口实现
26 * User: xjp
27 * Date: 2015/6/3
28 * Time: 15:40
29 */
30
31 public class WeatherModelImpl implements WeatherModel {
32
33 @Override
34 public void getWeather(String cityNumber, final OnWeatherListener listener) {
35
36 /*数据层操作*/
37 VolleyRequest.newInstance().newGsonRequest(http://www.weather.com.cn/data/sk/ + cityNumber + .html,
38 Weather.class, new Response.Listener<weather>() {
39 @Override
40 public void onResponse(Weather weather) {
41 if (weather != null) {
42 listener.onSuccess(weather);
43 } else {
44 listener.onError();
45 }
46 }
47 }, new Response.ErrorListener() {
48 @Override
49 public void onErrorResponse(VolleyError error) {
50 listener.onError();
51 }
52 });
53 }
54 }
以上代码看出,这里设计了一个WeatherModel模型接口,然后实现了接口WeatherModelImpl类。controller控制器activity调用WeatherModelImpl类中的方法发起网络请求,然后通过实现OnWeatherListener接口来获得网络请求的结果通知View视图层更新UI 。至此,Activity就将View视图显示和Model模型数据处理隔离开了。activity担当contronller完成了model和view之间的协调作用。
至于这里为什么不直接设计成类里面的一个getWeather()方法直接请求网络数据?你考虑下这种情况:现在代码中的网络请求是使用Volley框架来实现的,如果哪天老板非要你使用Afinal框架实现网络请求,你怎么解决问题?难道是修改 getWeather()方法的实现? no no no,这样修改不仅破坏了以前的代码,而且还不利于维护, 考虑到以后代码的扩展和维护性,我们选择设计接口的方式来解决着一个问题,我们实现另外一个WeatherModelWithAfinalImpl类,继承自WeatherModel,重写里面的方法,这样不仅保留了以前的WeatherModelImpl类请求网络方式,还增加了WeatherModelWithAfinalImpl类的请求方式。Activity调用代码无需要任何修改。
MVC使用总结
利用MVC设计模式,使得这个天气预报小项目有了很好的可扩展和维护性,当需要改变UI显示的时候,无需修改Contronller(控制器)Activity的代码和Model(模型)WeatherModel模型中的业务逻辑代码,很好的将业务逻辑和界面显示分离。
在Android项目中,业务逻辑,数据处理等担任了Model(模型)角色,XML界面显示等担任了View(视图)角色,Activity担任了Contronller(控制器)角色。contronller(控制器)是一个中间桥梁的作用,通过接口通信来协同 View(视图)和 Model(模型)工作,起到了两者之间的通信作用。
什么时候适合使用MVC设计模式?当然一个小的项目且无需频繁修改需求就不用MVC框架来设计了,那样反而觉得代码过度设计,代码臃肿。一般在大的项目中,且业务逻辑处理复杂,页面显示比较多,需要模块化设计的项目使用MVC就有足够的优势了。
在MVC模式中我们发现,其实控制器Activity主要是起到解耦作用,将View视图和Model模型分离,虽然Activity起到交互作用,但是找Activity中有很多关于视图UI的显示代码,因此View视图和Activity控制器并不是完全分离的,也就是说一部分View视图和Contronller控制器Activity是绑定在一个类中的。
MVC的优点:
耦合性低。所谓耦合性就是模块代码之间的关联程度。利用MVC框架使得View(视图)层和Model(模型)层可以很好的分离,这样就达到了解耦的目的,所以耦合性低,减少模块代码之间的相互影响。
可扩展性好。由于耦合性低,添加需求,扩展代码就可以减少修改之前的代码,降低bug的出现率。
模块职责划分明确。主要划分层M,V,C三个模块,利于代码的维护。
以上是关于MVC设计思想的主要内容,如果未能解决你的问题,请参考以下文章