前言#
最近忙于找工作,大家都知道今年移动开发是动荡的一年,在经济危机和创业潮退去的影响下,android和ios必须要面对供大于求的现状。
所以再看了招聘信息之后,发现对于设计模式的要求还是很高的,所以决定写几篇有关于设计模式的文章分享给大家。
第一篇就是最常见的MVC模式。
正文#
MVC应该是一开始接触Java最先听到的模式,尤其是Java的后端开发框架,在xml中配置xxxController,然后通过对应的Controller进行操作,是非常典型的MVC模式。
首先我们来看看MVC的架构图:
图是从其他博客上的盗的,在这里感谢原作者辛苦的画出来。
在看概念之前,我们来分析一下图中的架构:
从图可看出:
Controller是作为一个媒介,处于Model和View之间;
Model和View之间有紧密的联系,耦合性偏强。
Controller不建议直接操作View。
Model不建议直接操作Controller。
ok,下面来看一下概念:
Model: 处理要显示的内容
View: 显示内容
Controller: 格式化model和接收用户的操作事件。
诶,是不是有一种似懂非懂的感觉,那就赶紧实际来写点东西,加深一下理解,首先来看一个未使用mvc模式的简单demo:
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
loading();
}
/**
* 模拟一个loading请求
*/
private void loading() {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 模拟得到了数据现在开始处理
runOnUiThread(new Runnable() {
@Override
public void run() {
setLoadStatus(dealResult(LoadStatus.LOAD_SUCCESS));
}
});
}
}.start();
}
private String dealResult(LoadStatus status) {
switch (status) {
case LOADING:
return "loading...";
case LOAD_SUCCESS:
return "load success";
case LOAD_FAILED:
return "loading failed";
default:
return "";
}
}
private void setLoadStatus(String text) {
textView.setText(text);
}
}
代码非常的简单,就是模拟一个加载请求然后根据得到的结果显示一串文字,其中LoadStatus是一个枚举类,里面有三个状态,大家一看就懂,我就不贴出来了。
下面我们来对他进行mvc架构的改造,首先来强化一下的概念,弄清楚我们需要准备的工作:
MainModel:Model层,负责处理MainActivity要显示的数据。
MainView:负责显示MainActivity中的控件和交互操作。
MainActivity:很明显,他就是Controller,负责接收用户的操作事件。
创建完这三个文件,从习惯上肯定要从View层入手,先看看MainView的代码:
/**
* Created by li.zhipeng on 2017/3/27.
*
* MainActivity的View层
*/
public class MainView implements View.OnClickListener, MainModel.OnStringCallback{
private MainActivity activity;
private OnTextViewClickListener callback;
private TextView textView;
public MainView(MainActivity activity, OnTextViewClickListener callback) {
this.activity = activity;
this.callback = callback;
initView();
}
/**
* 初始化
* */
private void initView() {
textView = (TextView) activity.findViewById(R.id.textView);
textView.setOnClickListener(this);
}
/**
* 设置显示的文字
* */
public void setLoadStatus(String text) {
textView.setText(text);
}
/**
* 界面交互,要更新显示的文字
* */
@Override
public void onClick(View v) {
callback.OnTextViewClickListener((TextView) v);
}
/**
* 销毁释放资源
* */
public void onDestroy(){
this.activity = null;
this.callback = null;
}
@Override
public void onResult(LoadStatus status) {
setLoadStatus(MainModel.dealResult(status));
}
/**
* 处理结果的回调函数
*/
public interface OnTextViewClickListener {
void OnTextViewClickListener(TextView textView);
}
}
里面已经有各个方法的注释,MainView初始化控件,并设置各种响应事件:例如点击,然后通过回调函数传给MainActivity,然MainActivity来发送具体要操作的指令,实现了MainModel的Callback,等待MainModel把要显示的内容发过来。
然后来看看MainModel:
/**
* Created by li.zhipeng on 2017/3/27.
*
* 负责处理数据的Model层
*/
public class MainModel {
/**
* 加载信息
* */
public static void loadInfo(final OnStringCallback callback) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
switch (new Random().nextInt(2)) {
case 0:
callback.onResult(LOAD_SUCCESS);
break;
case 1:
callback.onResult(LOAD_FAILED);
break;
case 2:
callback.onResult(LOADING);
break;
}
}
}.start();
}
/**
* 处理并显示相应的文字
* */
public static String dealResult(LoadStatus status) {
switch (status) {
case LOADING:
return "loading...";
case LOAD_SUCCESS:
return "load success";
case LOAD_FAILED:
return"loading failed";
default:
return "";
}
}
/**
* 处理结果的回调函数
*/
public interface OnStringCallback {
void onResult(LoadStatus status);
}
}
MainModel中有加载信息和处理信息的方法,还有之前MainView实现的Callback。非常简单,没什么可说的,最后就是MainActivity了:
public class MainActivity extends AppCompatActivity implements MainView.OnTextViewClickListener{
private MainView mainView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainView = new MainView(this, this);
// 向model发送指令,开始得到数据
MainModel.loadInfo(mainView);
}
@Override
protected void onDestroy() {
super.onDestroy();
this.mainView.onDestroy();
}
@Override
public void OnTextViewClickListener(TextView textView) {
// 已经得到了数据,对处理进行处理
MainModel.loadInfo(mainView);
}
}
MainActivity就是我们的Controller,也就是大哥,负责发送具体的指令,告诉Model:赶紧加载数据给MainView!!
Model乖乖的加载完数据,传给了MainView:我搞定了,你赶紧显示吧...
MainView说你给我这个我也看不懂啊,你再处理处理...
Model再根据LoadStatus,返回给MainView一个字符串:我发给你了啊,你赶紧显示...
MainView说very ok。
第一波流程结束。
然后风骚的用户点击了textView,MainView对MainAcitivity说:大哥,用户点了我咋整?
MainActivity 对 MainModel说:别废话,赶紧再准备一份数据给MainView!!
Model乖乖的加载完数据,传给了MainView:我搞定了,你赶紧显示吧...
MainView说你给我这个我也看不懂啊,你再处理处理...
Model再根据LoadStatus,返回给MainView一个字符串:我发给你了啊,你赶紧显示...
MainView说very ok。
这就是传说中的MVC模式!!!
总结#
让我们最后来分析一下:
从模块结构上看:
1、MainActivity通过雇佣了两个小弟View和Model,把自己包装成大哥Controller,分工明确,大哥Controller除了发号施令,一身轻松。
2、增加了工作量和负担,View和Model的出现,代码量明显要上升了。
从后期维护上看
1、较之前相比,工作划分有了很大的划分,Controller只负责发号施令,剩下的工作交给了View和Model协调解决,后期便于维护查找。
2、Controller把具体的工作甩的干干净净,一旦出现了问题,我们就只能找小弟View和Model解决,并且View和Model耦合性高,私底下有一些不可描述PY交易,一旦出现问题,他俩可能要互相甩锅。
架构图上不建议Controller直接操作View,但是这个有时候不好说,例如如果是点击了textView,隐藏或显示另一个控件,那就直接操作mainView就可以了。当然你也可以在MainView中自己去隐藏和显示,但是这就更加违背了MVC一开始的设计规则,也不能把显示控件划分到Model中。这三者难免要进行取舍,这也体现了MVC在这一方面的设计的缺点。
MVC适合什么样的项目呢?个人觉得不适合小型项目,毕竟功能模块的分离还是很复杂的,需要耗费时间去设计,如果是交接的话,一个界面要看三个文件还是挺费劲的,但是每个人的侧重点不一样,大家自己考虑之后再做定夺。
到此为止,MVC模式就介绍完了,我们已经对MVC有了深入的了解,但是还需要多多练习,仔细体会MVC的优劣,demo仅供参考,如果你有更好的MVC模块划分和更好的理解,欢迎留言大家一起进步。
下一篇我们来谈一谈 MVP模式。
源码下载链接