MVP那些事儿(3)……在Android中使用MVC(上)设计模式
MVP那些事儿(4)……在Android中使用MVC(下)缓存
若是你要想更佳深入的理解MVP,并在实际开发中灵活的应用,那么就要先了解它的低配版MVC,他俩只是一步之遥,先了解MVC再学习MVP,MVP的优点才能凸显出来,这样连贯性的学习才会加深对MVP的理解。框架
咱们在上一章提到,MVP那些事儿(2) 用场景说话 对咱们的案例进行MVC的设计,也就是第一步,如何实现一个MVC,在实现以前咱们先搞清楚几点概念。异步
MVC属于分层架构中的一员,不管是哪个层从复用性和扩展性都是由当前业务所限制的,若是一开始就从复用和扩展上做为出发点来使用MVC的话,必定要有足够的开发经验(并非不能够,分层架构也是能够有扩展性的,但要考虑主次),除非你很是明确将来软件的复杂度。举个例子,好比有一个算法,它处理一组数据所需的时间关系以下:10条,须要1秒,20条须要1.8秒,30条须要2.5秒,,,,100条须要6秒,这个时间复杂度能够看出什么,能够看出这个算法处理的数据量越大,它的处理所消耗的时间递增越缓慢,也就越是大数据量越能体现它的价值,再举一个实际中的例子,人均100的餐厅,两我的去也许每一个人只能尝到2~3种菜样,但四我的去,每一个人会尝到4~6菜样,20我的去,你也许能够把他们家的菜尝个遍,MVC也是如此,软件的复杂度越高,越能体现MVC的扩展价值,这就是我为何要讲不要一上来就想从扩展性做为使用MVC的出发点,除非你是一个颇有经验的人,能提早估计出项目的一个大体的复杂度。更稳妥的方式应该是在项目的推动中不断的优化本身的架构,不少萌新会进入到误区,一看MVP你们都在用,本身设计一个吧,到最后发现根本就你一我的在吃菜,更关键的是别人想和你吃也吃不了,不通用,根本没法体现它的扩展价值,负责人发现后第一反应是,你搞这么多接口抽象类干什么?就你一我的用,搞事情。 布局
一个只为了分层就能够被叫作设计模式的话,那么外观模式看来还不是最尴尬的模式,因此它不能简单的称呼为设计模式,由于它的范围和深度更加立体,称为架构更为稳当,固然也能够称之为复合设计模式,它里面包含了,策略,组合,观察者,等设计模式。那么,架构和框架的关系又是什么呢?
MVC是一种架构思想,而基于这个思想的框架也叫MVC框架,在ios的开发中,系统为咱们实现了公共的视图类UIView,和控制器类UIViewController,还有大名鼎鼎的Struts2框架,都是基于MVC架构设计出来的框架(基于MVVM架构的DataBinding,Architecture Components框架),框架是一个有边界的可扩展集,它在可扩展的同时也是有边界的,也就是说你只能在这个框架里玩耍,而没法超出这个框框。若是你只是在项目中使用了MVC的思想去作分层,那么这个项目或模块用的就是MVC架构设计,若是你用了Struts框架,那么这个项目使用了MVC框架。当你向别人介绍你的项目时,你能够这么说:个人项目使用的是MVVM架构,具体用到了Architecture Components做为框架来进行开发,千万不要说成:你们好,我来介绍一款基于MVVM框架设计的Architecture Components架构,这听的得多别扭啊。
一句话总结——架构是蓝图,而框架是实实在在的产品,MVP架构就一个,而基于MVP架构设计的框架能够是千千万万个。
以上就是对MVC的一个大体的介绍,学习MVC以前,要先会写,学会了写,再学习用,接下来咱们先实现一个MVC框架。
在第一章的场景里咱们挑一个需求,咱们来实现一个向服务端请求数据,并显示在列表的需求。
public class TasksActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
//...初始化
//请求列表数据
Data data = loadData();
}
void onDataCallBack (Data data) {
//更新列表
upDateList(data);
}
}
复制代码
这是一段简单的示例代码,一般状况下咱们用像loadData这样的方法去请求数据,而且绑定监听,监听数据的返回,当数据返回时,像onDataCallBack这样的回调方法会被触发,同时进行ui的更新。
MVC分别为Model,View,Controller,顾名思义,首先咱们须要建立这三个对象,第二步,咱们把这三个对象组合起来,咱们先一个一个的认识它们,逐个击破,首先从简单的来,Model,
逻辑层(领域层)Domain Object,逻辑执行体,除此以外也能够兼顾JavaBean的职责,但Model层可不是简单的Value Object。而 JavaBean也就是Value Object,只是用来封装数据,不具有Model层的职责,固然也能够把JavaBean看成Model类的一个内部类来使用,固然也能够单独一个类,一般咱们也会这么做,方便复用。 萌新⚠️
一、JavaBean不是Model,但Model也能够包含JavaBean的职责,但不是必须的。 二、Model是用来处理数据的,如获取数据(本地或者服务端),数据处理,如CURD。
按照上面的定义咱们来写一个Model
/**我是一个Model**/
public class TasksRepository {
//从服务器请求获取数据
void getTasks() {}
//从内存缓存获取数据
Data getTaskCache() {}
//从磁盘缓存获取数据
Data getTaskDiskCache(){}
//保存一条数据
boolean saveTask(Task task) {}
//对数据进行排序
Data orderData(Data data, int orderType){}
}
复制代码
首先咱们建立一个Model类名为TasksRepository,首先不要关内心面的Data和Task对象,它们只是普通的Bean对象,TasksRepository里面包含了五个方法,按照以前的定义,它是有获取数据的职责的,因此这其中三个方法都是和获取数据相关,好比getTasks,你能够调用网络组件进行数据的获取,它还能够对数据进行CURD的操做,好比savaTask的方法用来保存一条数据,还能够对数据进行业务处理,好比用orderData方法对数据进行从新的排序。
一句话总结,Model负责获取数据,操做数据,和对数据进行业务处理。
接下来咱们讲一讲View,View就是咱们的视图层。
一、它的主要职责为呈现Model的数据、主动询问状态或被动的监听 二、通知控制器Controller去处理一些事情 三、接收Controller,编辑本身与Model无关的状态
按照View的职责咱们来设计一下这个类
/**我是一个View**/
public class TaskView {
//当列表初始化后,告诉控制器该加载数据了
void viewCreate() {
controller.loadNomData();
}
//更新列表
void upDateList() {
//主动请求Model获取数据
Data data = tasksRepository.getTaskCache();
//更新ui
list.update(data);
}
void beginLoadData(){
list.showHead();
}
}
复制代码
在TaskView中也就是咱们的视图对象,它包含了俩个对象,分别为controller和taskeRepository,controller就是控制器对象,咱们下一个讲它,taskeRepository就是咱们的模型,上面提到过它,先不要关心这两个对象是怎么初始化来的,要关心的是View视图对象是包含了C和M的,按照职责它必须这么作,首先像viewCreate这类方法通常是在界面初始化时调用的(在Android 中多是Activity或者Fragment初始化时调用的,也多是某一个执行动做),让controller去执行loadNomData的方法请求数据,这里惟一须要注意的是,并无明确的告诉controller请求的数据是从什么地方来的,也许是缓存,也许是网络请求,view是无需关心这一点的。同时还要注意的是,在讲解Model的时候已经明确了Model是有获取数据的职责,可是在上面的示例中,**为何是controller去负责获取数据,而不是用Model?也就是咱们的tasksRepository对象?**请你们记住这个疑问,会在讲解Controller时回答。
第二个方法upDataList方法,
//更新列表
void upDateList() {
//主动请求Model获取数据
Data data = tasksRepository.getTaskCache();
//更新ui
list.update(data);
}
复制代码
它的内部是经过tasksRepository对象的getTaskCache()方法获取数据,这个方法在Model的定义里面,你们还有印象吧。讲到这里,**你们可能发现有一个严重的漏洞,view在执行tasksRepository.getTaskCache()时,是怎么知道这个数据已经准备好了呢?**看view的职责1:
主动的问询或者监听Model
咱们把调用tasksRepository.getTaskCache()看做为主动的问询,而在主动问询前,View应该获得一个有效的通知,这个通知应该由Model发起,当监听到Model:个人数据准备好了,你来拿吧时,View会去主动的向Model获取数据。举个现实中的例子,你在网上买东西,如今通常都往快递柜里投放,等到短信通知你快递到了时,你才会去快递柜里拿商品,但也许你实在等不及了,也能够每天打电话,咱们就不详细讨论了,View和Model但关系也就是观察者与被观察者的关系。但是,在上面的示例中咱们没有写出监听Model的代码,请你们记住这个疑问,我会在后面讲解三者的依赖绑定时会揭晓答案。 最后一个方法,beginLoadData(),
void beginLoadData(){
list.showHead();
}
复制代码
当开始请求数据时,list会显示本身的头布局,像beginLoadData这样编辑view自己的方法在实际开发过程当中还有不少,它们关注的是控件自己的状态,最重要的,这样的方法可能会被Controller随时的调用,咱们在讲解Controller时进行讲解。
Controller,也就是咱们的控制器,它把视图的操做发送到模型。
接收View的操做,并转调给Model 改变View的状态
按照上面的职责,咱们尝试的设计一下这个类:
/**我是一个Contorller**/
public class TasksController {
void loadNomData() {
if(tasksRepository.getTaskCache() == null){
//执行Modle
tasksRepository.getTasks();
//执行View
view.beginLoadData();
}
}
}
复制代码
在对Controller讲解以前,咱们先停顿一下,在以前的介绍中咱们好像遗留了几个问题,在介绍View时,我用加租文字的方式标示了三个问题,在介绍Controller时咱们将要解决掉问题1,和问题3。咱们一块儿回顾一下这2个问题:
疑问1,在讲解Model的时候已经明确了Model是有获取数据的职责,可是在上面的示例中,为何是controller.loadNomData()去负责获取数据,而不是用Model?也就是咱们的tasksRepository对象?
这个问题要从Contrller的职责提及:接收view的操做,并转调给Modle。什么是view的操做,好比list的下拉刷新操做,转调给Model,也就是说其实Controller并无实际的实现加载数据的代码,而是让Model去执行,解释完之后,看一下TasksController里的第一个方法loadNomData(),
void loadNomData() {
if(tasksRepository.getTaskCache() == null){
//执行Modle
tasksRepository.getTasks();
//执行View
view.beginLoadData();
}
}
复制代码
它内部第一条语句:
tasksRepository.getTasks();
复制代码
而tasksRepositor对象就是咱们的Model,它执行了getTasks()的操做,其实controller的loadNomData()方法只是对这个过程进行了一个封装。听完上面的解释,咱们知道Controller是这么设计的,但是又一个问题出现了,虽然咱们知道了Controller转调了Model的方法,但是我为何要这么作?我直接在View里调用tasksRepository.getTasks();不能够吗? 清你们记住这个问题,我下一章为你们解答,咱们先学会写,再去研究怎么用。
疑问2,像beginLoadData这样编辑View自己状态的方法在实际开发过程当中还有不少,它们纯粹关注的是控件自己的状态,最重要的,这样的方法可能会被Controller随时的调用。
咱们先回顾一下这个方法beginLoadData()
//controller会随时调用
void beginLoadData(){
//显示列表的头部,改变了列表的属性
list.showHead();
}
复制代码
咱们仍是从Controller的职责来讲,Controller有权利对View的状态进行改变,无论是通知的形式,仍是直接的访问。并且View的职责里也说明了,它是能够接收Controller更改本身的状态,而更关键的一点这个状态的改变是无需依赖Model的,更加的纯粹。
有了上面问题的承上启下,咱们再回头看一下TasksController里的loadNomData()方法,它首先判断了是否能够从tasksRepository里拿到缓存,若是没有就执行getTasks(),同时通知view我要开始加载数据了,view会在beginLoadData()方法中对本身的列表控件进行一个显示头部的处理,至关规范的一个封装。
**总结:**到此,咱们已经学习完了MVC这三个层的定义和职责。在文章的开头我有讲过,要想用MVP,就要先用MVC,要想用MVC就要先会"写"MVC,写才是第一步,咱们首先把MVC这三个层,拆分红三个片断,每个片断都规范好它们的职责,而后咱们再想办法把它在组装在一块儿,在下一章咱们要解决如下问题:
一、如何把这三个片断组装起来?在Android里怎么写? 二、view在执行tasksRepository.getTaskCache()时,是怎么知道tasksRepository数据已经准备好了呢?怎么通知view的?
谢谢你们关注和评论,更新的有些慢,不如关注我一下,随时知道更新进度。