IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 站在思想层面看MVX架构 -> 正文阅读

[开发测试]站在思想层面看MVX架构

程序的本质

程序的本质在于模拟现实,但是有更明确的分工

简单的一个例子: 我 写 代码。

这是一个主谓结构: 主语->我,谓语->写,宾语->代码。

现在让我们来面向视角看问题:

  • 代码: 是个物体,是用来 被 写 的
  • 写: 是个动作,是用来 被 我执行的
  • 我: 是个物体,是用来 执行 写 这个动作 写代码的。

好,接着我们来面向对象写代码:

首先,创建一个我,这是个物体,所以应该创建一个对象:

public class Me {

}

然后,需要有代码,才能写,代码也是一个物体,那么再创建一个对象:

public class Code {

}

等等,代码应该有内容,有注释,好,我们来简单模拟下(程序就是模拟现实的):

public class Code {
    // 代码
    public String code;
    // 注释
    public String comment;
}

最后,需要创建一个写的动作,写既然是一个动作,不是物体,那么肯定是属于某个物体的行为,这里就是我的行为,动作就是函数(接口),于是就在 "我" 里面添加函数:

public class Me {
    // 添加写的行为,写什么?写代码
    public Code write() {
        Code code = new Code();
        code.code = "This is code";
        return code;
    }
}

这里有个问题,写过的代码,怎么展示出来呢,我们需要个显示器来显示,显示器是物体,所以我们需要定义个对象:

public class Display {
    // 显示器可以显示内容
    public void display(String content) {
        System.out.println(content);
    }
}

然后,我们需要展示我们的代码,我们可以直接这样改:

public class Me {
    // 添加写的行为,写什么?写代码
    public Code write() {

        // 写代码
        Code code = new Code();
        code.code = "This is code";
        
        // 展示
        Display display  = new Display();
        display.display(code.code);
        return code;
    }
}

这样当然没问题,但是,write()明明是一个写的函数,却额外做了展示的事情,不满足SRP,万一我只想写,不想展示呢,所以我们将函数分离职责,如下:

public class Me {
    // 添加写的行为,写什么?写代码
    public Code write() {

        // 写代码
        Code code = new Code();
        code.code = "This is code";
        return code;
    }

    // 展示代码
    public void showCode(){
        
        // 写代码
        Code code = write();

        // 展示
        Display display  = new Display();
        display.display(code.code);
    }
}

这样也不对,因为showCode()里面又调用了写的动作,showCode()应该只负责展示代码的,怎么办呢?追起根源,展示代码这个动作,并不是我自己的行为,所以不应该放在Me里面,任何人都可以展示代码,比如,我把自己的代码提供给第三方,第三方只要拿着显示器,就能展示出来,所以,展示代码这个事情,应该是属于第三方的,好,现在我们把Me里面的showCode()删掉,创建一个第三方场景类:

public class Client {
    // 展示代码
    public void showCode(){
        
        // 我来提供代码
        Me me = new Me();
        Code code = me.write();

        // 让显示器来展示
        Display display  = new Display();
        display.display(code.code);
    }
}

上面我们绕了一大圈,最后也就这么一句话: 我在Client中写了代码,然后把它展示了出来。用程序的话来说就是 Client控制我写出Code,然后控制Display展示Code

这里我们就引出了最基础的架构思想: MVC。MVC的核心就是一句话: C控制M展示在V上,这里Client就是C,Code就是M,Display就是V,所以是Client控制Code展示在Display上。至于Me,是负责提供生产Code的,就像是服务器是负责提供数据的一样。

MVC

MVC就是:Model,View,Controller的简写,核心是职责分离

我们知道,计算机由: 控制器,运算器,存储器,输入设备和输出设备组成,这里就是: 控制器 控制 存储器里面的内容 展示在 输出设备 上。所以MVC是个广义的思想,他不是架构,是思想,可以是物理的,也可以是虚拟的。

MVC的核心就是一句话: C控制M展示在V上,精粹就是四个字职责分离

这里再强调一下,MVC是广义的概念,广义的就是思想,不是架构,或者从狭义来说,它也是一种架构。

我们来看下MVC的结构图:

MVC

这里我们可以看到,MVC本身的耦合是挺严重的,M和V竟然也有关联,这确实不应该的。但是MVC的核心是职责分离而不是解耦合,体现在设计上就是,MVC的核心是单一职责,而不是最少知识

在普通的Android应用中,M就是数据,V就是xml布局,C明显就是Activity。这里有点不太对劲儿,Activity明明更像一个View,因为它有findViewById()的方法,为什么又是C呢,这岂不是违背了MVC的职责分离明确的原则吗?这只能说谷歌设计的不太好。于是就有了下面的MVP模式。

MVP

MVP就是:Model,View,Presenter,这里把Controller替换为了Presenter。

MVP的核心除了MVC的职责分离,还有解耦合,也就是说,他在满足单一职责的基础上,又满足了最少知识原则。我们看下它的结构图:

MVP

这里我们看到,View和Model没有关联了,它们都通过Presenter来沟通,是不是有点像中介者模式。中介者模式的优点不就是解耦合吗,正好!

中介者模式

现在假如我们使用了MVP模式,我们的代码看起来是这样:

class Model {
    Presenter presenter;
}

class View {
    Presenter presenter;
}

class Presenter {
    Model model;
    View view;
}

可以看到,View和Model是零耦合的。

那么事件的流向就是: View -> Presenter -> Model

数据的流向就是: Model -> Presenter -> View

中间都需要经过Presenter。

当我们在Android中使用时,可以把Activity当作Presenter,把xml当作View,当然也可以直接把Activity抽空,自定义一个Presenter。这里我们来个简单的例子示例一下MVP中事件和数据的流向。

假设现在屏幕上有一个按钮,点击之后需要展示数据,事件肯定是屏幕引起的,也就是View,所以事件的出发点是View。

public class View {
    Presenter presenter;
    // 1 发出事件
    public void click(){
        presenter.getInfo();
    }

    // 6 接收并展示数据
    public void showInfo(String info){
        setInto(info);
    }
}

public class Presenter {
    Model model;
    View view;

    // 2 传递事件
    public void getInfo(){
        model.getInfo();
    }

    // 5 传递数据
    public void onGetInfo(String info){
        view.showInfo(info);
    }
}

public class Model {
    Presenter presenter;
    
    // 3 接收并处理事件
    public void getInfo(){
        String info = getInfoFromServer();
        
        // 4 发出数据
        presenter.onGetInfo(info);
    }

    // 模拟从服务器获取数据
    private String getInfoFromServer(){
        String info =  "this is info";
        return info;
    }
}

事件的流向(1->2->3): View.click() -> presenter.getInfo() -> model.getInfo() -> 从服务器获取数据。

数据的流向(4->5->6): model.getInfo() -> presenter.onGetInfo(info) -> view.showInfo(info) -> 展示在屏幕上。

可以看到,View是事件的发起者和数据的接收者,Model是事件的接收者和数据的发起者,Presenter只是起个中转作用

好,现在我们知道了MVP除了具有MVC的职责分离优点,还能解耦合。接下来我们来看自动化的MVP-MVVM

MVVM

MVVM就是: Model,View,ViewModel。

MVVM的核心是观察者模式,MVVM已经不再职责分离了,当然也没解耦合,他的特点就是响应式。什么意思呢,就是说: 我这边数据变了,你那边立刻知道,不需要经过谁来通知。

MVVM

官方的图是这样的,View和Modle无关联,但是这是不严谨的,因为对于MVVM来说,Model数据变了后,需要通知到View,那么肯定需要直接或间接持有View的引用,所以这个图是不严谨的。

我们将上述MVP的代码改写为MVVM。

class View {
    ViewModel vm;

    // 订阅Model的数据
    private void init(){
        vm.getModel.observer(content, new Observer() {
            public void onInfo(String info) {
                // 6 接收到数据并展示
                showInfo(info);
            }
        })
    }

    // 1 发起事件
    private void click(){
        vm.getInfo();
    }

    // 7 展示数据
    private void showInfo(String info){
        setInfo(info);
    }
}

class ViewModel {
    
    Model model;

    Model getModel(){
        return model;
    }

    // 2 传递事件
    public void getInfo(){
        model.getIndo();
    }
}

class Model {

    // 定义观察者,这里已经持有观察者了,也就是持有View了。
    List<Observer> observers;

    // 添加观察者
    public void observe(Observer observe){
        observers.add(observe);
    }

    // 3 接收并处理事件
    public void getInfo(){
        // 4 获取数据
        String info = getInfo();
        // 5 通知数据改动
        for(Observer observer : observers) {
            observer.onInfo(info);
        }
    }

    // 模拟从服务器获取数据
    private String getInfoFromServer(){
        String info =  "this is info";
        return info;
    }
}

经过上面伪代码,我们发现ViewModel只传递了事件,不再传递数据了,数据是直接由Model通知到View的,所以我们的:

事件流向: View.click() -> ViewModel.getInfo() -> Model.getInfo() -> 获取数据。

数据流向: Model.getInfo() -> View.Observer.onInfo(info) -> View.showInfo() -> 展示数据。

这里有个很egg pain的点,就是Model间接持有View,第一就是会导致耦合,第二就是可能发生内存泄漏,我们知道Model的生命周期是大于View的,所以要在View消失的时候去反注册掉。当然,使用LiveData可以更好的解决问题。

那么,MVVM的优点在哪呢?就是你不用去主动去刷新UI了,只要Model数据变了,会自动反映到UI上。换句话说,MVVM更像是自动化的MVP

总结

  • MVC更像是一种思想,它描述一种职责分离的思想
  • MVP是MVC的一种表现,它出了具备职责分离,还具备解耦合
  • MVVM是自动化的MVVM,它具备职责分离,具备松耦合,同时还能自动响应数据。

如果你的业务是少量的重逻辑,建议使用MVP(debug方便);如果你的业务是大量的轻逻辑,最好使用MVVM(自动响应数据方便)。

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:59:40  更:2021-08-23 17:00:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 22:24:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码