MVP那些事儿 (4) 在Android中使用MVC(下)

为何要先介绍MVC?

若是你要想更佳深入的理解MVP,并在实际开发中灵活的应用,那么就要先了解它的低配版MVC,他俩只是一步之遥,先了解MVC再学习MVP,MVP的优点才能凸显出来,这样连贯性的学习才会加深对MVP的理解。缓存

目录

MVP那些事儿(1)……用场景说话服务器

MVP那些事儿(2)……MVC架构初探架构

MVP那些事儿(3)……在Android中使用MVC(上)框架

MVP那些事儿(4)……在Android中使用MVC(下)ide

MVP那些事儿(5)……中介者模式与MVP的关系函数

MVP那些事儿(6)……MVC变身为MVP工具

MVP那些事儿(7)……Repository设计分析post

快速回顾

MVP那些事儿(3)……在Android中使用MVC(上)学习

在上一篇中,咱们学习了MVC架构图原理和它的进化过程,并经过is a,has a,依赖注入原则对MVC中三个对象进行组合,同时从无到有的搭建出MVC框架的基本雏形,ui

灵与骨,血与肉

在上一篇中,咱们的MVC框架已经完成了初步的搭建,固然,还不是框架最终形态,虽然三个对象经过某种联系组合了起来,但让框架真正运转起来还须要最关键的一个机制,那就是沟通机制,就比如人类,光有骨架和血肉还不能称之为一个完整的“人”,你还须要神经系统帮助你去看,听,和感觉。

沟通机制

在Java的面向对象设计中,监听是一种经常使用的沟通机制,在观察者模式里,一个监听机制所涉及到的对象包括:监听者(Observer)、被监听者(Obserable);涉及到的环节包括:订阅(Subscribe)、发送事件、及处理事件。

场景

使用如下两个需求做为本章场景:

一、列表展现

二、列表支持下拉刷新,上拉加载更多

实现监听机制

既然监听是一个经常使用的沟通手段,咱们就开始“升级”咱们的框架

监听的好处

在开始以前,依旧要用一个场景来描述一下监听的好处,还记得以前租房子的故事吗?在这个故事里,我故意忽略了沟通的机制,就是为了留在这一章节讲的,当租客联系到中介时,这是一个主动的动做,租客是发起方,当和中介创建联系后,他们双方互留电话,同时中介找到合适的房东,而且也留下了联系方式,这个时候中介开始等待房东的回应,这期间中介什么都干不了,一分钟一个电话的询问房东是否考虑好了,那么中介的下场只有两个,房东很生气,一分钟一个电话,你没事儿,我还有事儿呢,你等我消息不行吗?直接拉黑。或者因为中介一次只能处理一个事情,这件事处理不完,就不能处理下一件事,效率低下被公司开除。租客也是同样,一次次的去询问中介,找到房子了吗?等待他的下场也有两个,1、一次次的电话,致使电话费报表,2、因为电话费太贵,打算一天问一次,因为获取消息不及时,结果房子被别人租走了,也就是消息的即时性低,而露宿街头(虽朱门酒肉臭,但别路有冻死骨,愿在外漂泊的大家在这寒冷的冬天里有一个温暖的所在)。

为了不上面的悲剧发生,中介公司改善了沟通机制,首先从租户的角度,经过主动向租客汇报进度来解决消息即时性的问题,让租户第一时间获得最新状况,其次,中介再也不催促房东,而是让房东考虑好后通知中介,当中介收到房东的消息后第一时间通知给租户,经过这两个环节的改造,一条高效的通知链就造成了。

为MVC框架增长监听

Modle的职责是对数据的生产和处理,并在结束一些耗时的操做后,应该主动的通知给Controller,因此Model为被观察对象,而Controller为观察对象,它观察着Model的一举一动,为了能更好的观察Model的行为,Controller派了一个“眼线”到Model中,这个“眼线”的职责就是监听Model的一举一动。

第一步,定义一个“眼线”

/**我是一个“眼线”
public interface Observer {}
复制代码

这里的眼线就是一个观察对象的接口,但具体让它作什么,咱们还不清楚,经过接口的形式将来会有很好的扩展性,定义完眼线,如何使用呢?

还记得上一篇中View是被怎么使用的吗?它被Actvity实现了,也便是说咱们这里的“眼线”也应该被某个对象去实现,不然它将没有任何用处,因为是Controller派出了一个“眼线”,因此应该由Controller去使用,使用的两种途径,要么本身具有“眼线”的功能,也就是is a,要么就是本身招募一个“眼线”,Has a。

一、我就是眼线,眼线就是我

/**我是一个Contorller,同时我就是个眼线**/
public class TasksController implements Observer{
    void loadNomData() {}
}
复制代码

TasksController,经过实现Observer接口,具有了观察者的能力。

二、我招了个眼线

/**我是一个Contorller**/
public class TasksController{
    //我招募了一名眼线
    private Observer observer = new Observer() {};
    void loadNomData() {}
}
复制代码

TasksController,经过内部实例化了一个Observer接口,间接的得到了观察者的能力。

以上两种均可以得到观察者的能力,可是从扩展性来说,仍是尽可能去选择第一种方式。

第二步,放置眼线

有了眼线后,咱们还要将它放置在被观察者的内部,这才算完成了观察者与被观察者之间的订阅。

public class MainActivity 
extends AppCompatActivity 
implments TasksView{
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,经过构造器注入
        TasksController controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.setController(controller);
    }
}
复制代码

这是上一篇内容中的代码段,将来都会围绕着这段代码进行改进,看最下面这一行:

model.setController(controller);
复制代码

其实,这一步就是model持有了controller,因为咱们如今的controller具有了观察者的职责,同时在咱们真正的使用中没有必要把整个controller的职责都暴露给model,而model也只须要controller观察者的能力,好让它即时的把结果告知controller,因此咱们能够这样改造一下这段代码为:

model.addObserver(observer: controller);
复制代码

看起来传的参数依旧是controller,只不过改了一个方法名,这没什么区别啊,我想说的是区别仍是有的,方法名的改变意味着这段代码的业务变了,虽然都是controller,没改以前是所有的controller,而下面的代码是告诉你们,我只使用controller观察者的部分,其余的我不关心,虽然你全给了我,但用那些是个人事情。

改造事后的Activity:

public class MainActivity
extends AppCompatActivity
implments TasksView{
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,经过构造器注入
        TasksController controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.addObserver(observer: controller);
    }
}
复制代码

第三步,发送事件

这个时候,Model已经获取到了观察者,也就是Controller,那么当Model本身发生变化时,就能够即时的通知给Controller了,咱们试着发一个事件,可是在发送事件前,不要忘了眼线尚未具体的能力,咱们只是定义了一个接口,眼线具体有什么能力仍是要结合具体业务去定义,这不属于架构的部分,更偏向于业务层,这里咱们就模拟当Model获取到数据后,通知Controller,我拿到数据了,因此让眼线有通知数据ok的功能:

/**我是一个“眼线”
public interface Observer {
    //数据OK
    void onDataComplate(Data data);
}
复制代码

目前眼线已经准备完毕,就等着Model来使用了,咱们用Model来发送一个事件

Model :TasksRepository

/**我是一个Model**/
    public class TasksRepository {
        //眼线集中营
        public static ArrayList<Observer> observers = 
            new ArrayList<Observer>();
        viod addObserver(Observer observer){
            observers.add(observer);
        }
        //从服务器请求获取数据
        void getTasks() {
            //访问服务器,耗时。。。服务器返回时,
            Data data = fromServer();
            //发送事件
            for(Observer observer : observers){
                observer.onDataComplate(data);
            }
        }
        //从内存缓存获取数据
        Data getTaskCache() {}
        //从磁盘缓存获取数据
        Data getTaskDiskCache(){}
        //保存一条数据
        boolean saveTask(Task task) {}
        //对数据进行排序
        Data orderData(Data data, int orderType){}
    }
复制代码

在实际的开发中,Model可不是只为了某一个Controller去监听的,它能够被任何想要监听它的人监听,你只要送一个眼线过来,当Modle有变更时,Model会通知全部关心它的人,因此Model里面有一个Observer的集合:

public ArrayList<Observer> observers = 
            new ArrayList<Observer>();
复制代码

当Model发生了变化,就会遍历这个集合去通知全部的观察者,而眼线在这里派上了用场

for(Observer observer : observers){
    observer.onDataComplate(data);
}
复制代码

第四步,接收事件

处理事件的特性是观察者的本质,Controller既然是观察者,那么处理事件应该由本身去完成:

Controller :TasksController

/**我是一个Contorller**/
public class TasksController implements Observer{
    //接收事件
    void onDataComplate(Data data) {
        //处理事件
    }
    void loadNomData() {}
}
复制代码

TasksController实现了Observer的onDataComplate方法,当Model发送事件后,onDataComplate方法便能接收到,咱们就能够在这里处理事件了,到此为止整个事件从建立处处理就完成了,这也就是观察者模式的核心,若是之后须要本身实现一个观察者模式,那么就按照上面四个步骤来写,绝对不会懵圈并且思路会异常的清晰。

那么View呢?

上面的场景提到过,当房东考虑好后通知给中介,中介会第一时间通知租客结果,那么具体改如何作呢?

public class MainActivity
extends AppCompatActivity
implments TasksView{
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,经过构造器注入
        TasksController controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.addObserver(observer: controller);
    }
}
复制代码

回过头来看Acivity的代码中的这一段:

//初始化Controller,this就是View,经过构造器注入
TasksController controller = 
            new TasksController(tasksView:this);
复制代码

首先,经过构造函数,让controller持有view,当controller接收到model的通知时,紧接着通知view,因此TasksController的代码还需改进:

/**我是一个Contorller**/
public class TasksController implements Observer{
    //经过构造函数接收view
    public TasksController(TasksView view) {
        this.view = view;
    }
    //接收事件
    void onDataComplate(Data data) {
        //处理事件,紧接着向view发送事件
        view.onDataBack(data);
    }
    void loadNomData() {}
}
复制代码

咱们看处理事件的部分,直接执行了view的方法,也就是所谓的即刻通知。

让View也接口化

按早以前Controller观察者化的思路,咱们能不能让view也变成观察者,固然能够并且是必须的,让view 去观察Controller的变化,Controller又去观察Model的变化,那么整个链式反应就完成了。具体步骤就不分析了,上一个完整的代码:

View :TasksView

/**我是一个View,我自己就是个眼线**/
    public interface TaskView {
        void onDataBack(Data);
        //当列表初始化后,告诉控制器该加载数据了
        void viewCreate();
        //更新列表
        void upDateList();
        //just for ui
        void beginLoadData();
    }
复制代码

Activity:

public class MainActivity
extends AppCompatActivity
implments TasksView{
    private TasksController controller;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Controller,this就是View,经过构造器注入
        controller = 
            new TasksController(tasksView:this);
        
        //初始化Model,Model -> View and View -> Model
        TasksRepository model = 
            new TasksRepository(tasksView:this);
        
        //Controller -> Model
        model.addObserver(observer: controller);
        viewCreate();
    }
    //接收controller的事件,并处理
    void onDataBack(Data){
        //处理事件。。。
    }
    //当列表初始化后,告诉控制器该加载数据了
    void viewCreate(){
        controller.loadNomData();
    }
    //更新列表
    void upDateList(){}
    //just for ui
    void beginLoadData(){}
}
复制代码

总结:

这一篇中,咱们经过观察者模式对咱们的框架进行了改进,经过监听,让MVC的三个对象造成了一个事件传送带,事件就比如有了方向通常从Model出发,通过Controller最终流向View,然后期咱们能够在这条链路上对咱们的事件作任何想要作的操做,而最终的接收者View是彻底不用关心的,亦或者view能够自定义本身想要的数据,在Model尚未发送事件前。说的更确切点,咱们能够在事件的发送前,传输中,接收前,这三个点作不少咱们但愿作的事情,好比数据在接收前的一些排序的转变,这些咱们都会以接口的 方式暴露出来。到此,MVC的介绍结束,但框架的搭建尚未完成,在接下来的被容里,咱们经过MVP的方式对框架进行进一步的改进,同时加入一些实质些的工具,让框架具有一些基本的业务功能。

相关文章
相关标签/搜索