【Android】常见的架构模式:MVC, MCP, MVVM

了解架构

  1. 架构的理解:
    1. 架构是为了解决某些问题而提出;
    2. 架构规定了一个系统中的组件/角色/模块的划分规则;
    3. 架构决定了这些不同的模块/角色的沟通机制;

结构是一种规则,一种架构有很多种实现的方式,没有对错之分,只有合适之分;

  1. 架构的学习:

    学习一个架构,我们要聚焦于架构解决了什么样的问题,从而根据我们遇到的问题去选择合适的架构;重点掌握架构它的思想,它的规则是什么样子的不同的角色是怎么划分的,最后要清楚这个架构的沟通机制;

    架构中通信的数据一般分为两种:数据结构,事件;

    1. 数据结构:网络请求,本地存储通信使用的javabeen
    2. 事件:控件产生的动作:触摸,点击,滑动等等;
  2. 常见的架构:

    常见的有mvc,mvp,mvvm,除了这些,还有cs(客户端-服务端模式),主从模式等等;

MVC

我们学习的线是: 如何划分职责->通信的流程->实现->解决了什么样子的痛点以及优缺点;

如何划分职责

MVC: model, view ,controller

model
  1. 定义:模型,负责数据的加载和存储;

  2. 职责:

    1. 从网络,数据库,文件里面加载或者存储数据;
    2. 封装业务逻辑:数据效验、数据转换、缓存策略;
    3. 不直接操作UI;
view
  1. 定义:视图,负责界面展示;

  2. 职责:

    1. 负责UI事件(点击),把用户的操作交给控制器;
    2. 显示model的数据;
Controller
  1. 定义:控制器,负责逻辑控制;

  2. 职责:

    1. 接收用户的输入;
    2. 调用model层的方法;
    3. 通知viiew更新UI;

数据流向:

view产生事件,然后通知给controller, controller作逻辑的处理,然后把数据通知给model,最后model进行数据的处理,最后通知给view更新UI;

具体实现:

  1. 其实在android 中,可以理解为一个mvc, xml文件就是一个view层,活动或者碎片可以理解为一个控制器层;

  2. 我们往往会在碎片或者活动中充当controller,model的角色,xml的view->所以碎片和活动中也会有view的角色;

  3. 引用持有:

    1. view中持有controller的引用和model的引用;

    2. controller中持有controller的引用;

    3. model持有view的引用;

    1是因为,我们需要在这里设置,使得2,3成立;

  4. 大致就是:规定三端接口,规定不同的方法,然后让三端实现对应接口的方法;在view调用c的方法,在c处理好数据调用m方法,以此类推;

优缺点

  1. 优点:

    在一定程度上降低了耦合,划分了职责;

  2. 缺点:

    1. Fragment/Activity里面还是很臃肿:因为它天然承担一些逻辑,既承担了view的角色,还有controller的角色;
    2. 解耦:如果直接修改view,controller和model都会受到影响;
    3. 增加了代码结构的复杂性;

    这里我想解释一下1,2;

    对于1,view和controller虽然是两个类,但是是碎片决定什么时候调用controller等等,这本来就承担了一部分逻辑;所以会导致碎片较为臃肿;

    对于2,为什么view的改动会使得controller,model收到影响;对于controller,比如我要取消某个按钮的点击,那么这个按钮对应的逻辑会失效;对于Model,因为Model持有view的引用,假如本来调用的view的方法是getname(),但是由于业务变动使得这个数据调用的方法是getxb();就会导致model中调用这个方法处全部报错,所以这就是问题了;

MVP

介绍

  1. MVP是MVC的改进,避免了UI组件直接与业务逻辑的耦合;解决了碎片/活动中臃肿,过渡耦合;

如何划分职责

  1. mvp-model、view 、presenter

    model
    1. 负责业务逻辑和数据的 处理,和p通信;
    view
    1. view不包含任何业务逻辑,view通过接口和p通信,把业务逻辑交给p来处理;
    presenter
    1. 作为model,view的中介,负责把model获得数据通知view更新,处理逻辑和决定如何将数据传递给view;

解决的问题

能解决mvc的问题:数据处理逻辑和界面交互相耦合,也能将mvc中的view和Model解耦:mvc中view可能直接访问Model获取数据,耦合度较高,但是mvp中,view不会直接访问Model,而是通过P层进行业务逻辑的处理以及负责view和model的交互;

数据流向

用户触发事件(点击按钮,输入文本)->view收到点击事件之后交给p层->p层做出业务逻辑处理->如有需要,把数据传递给Model->Model更新、储存、获取数据->将结果返回给P层->p层更新UI

具体实现

我的实现想法就是:

  1. 在活动里持有mvp三层的实例,在这里将p层进行构造方法依赖注入;
  2. 在v层通过方法注入,获得P层的实例,进行方法调用;
  3. 在m层可以通过方法注入,也可以通过接口回调(p层实现接口,在方法中传入自己,使得p,m通信,m回调时会回到p层,所以很容易造成接口臃肿);

看了一篇学长的博客,有两处代码需要我们学习:

  1. BaseView接口:

    • 里面只有一个方法,这个方法的作用是让v层都实现这个方法,获得p层的实例,输入方法注入;
    java 复制代码
    public interface BaseView<T>{
        /**
         * 为视图绑定对应的presenter
         *
         * @param presenter
         */
        void setPresenter(T presenter);
    }
    • 同时view接口去继承这个baseview接口
    java 复制代码
     interface View extends BaseView<Presenter> {
            void setMusicData(musicData musicData);
    
            void showError();
    
            /**
             * 用于判断Fragment是否成功加入到Activity
             *
             * @return {@link Boolean}
             */
            Boolean isACtive();
        }
    ```
  2. 单例:

    虽然但是,你真的打算创建很多model的实例吗?好吧,笔者天气预报就是这么写的,现在看来,,,感觉还是应该把架构好好学学,不然写的代码一坨有什么意义呢?

    好吧,那我们需要创建单例:

    以下是简单实现:

    java 复制代码
    public class danli {
        private static danli danli = null;
        public static danli getInstance(){
            if(danli == null){
                danli = new danli();
            }
            return danli;
        }
    }
    ```

好吧,其实我看了两位学长的博客,在他的博客里,我需要了解一下依赖注入;

刚说了那么多的注入,泥萌知道指的是啥吗?

好吧,我们刚一直在说,mvc,mvp解决了业务逻辑和UI耦合的问题,实现了解耦,那么到底怎么解耦的?

高内聚,低耦合:类的内部元素(方法定义)应该紧密相关,与外部类的依赖关系应该降低;

  1. 接口

    1. 定义了两个模块的交互规则;使得两个模块通过接口交互,不依赖具体的类;
    2. 举例:view 和 presenter: view可以很容易的替换, 不会依赖具体的view类;
  2. 依赖注入:

    • 介绍:是一种设计模式,将对象的依赖关系从内部创建变成外部传递,从而到达解耦的地步;介绍模块之间的!直接!依赖;

    • 实现方法:构造函数注入,方法注入,属性注入;

      其实听名字就很好理解了啊,构造函数注入就是通过构造方法传入实例,mvp中就是通过构造函数注入把v,m注入p层的;方法注入就是通过方法调用啊,mvp中在v层就是通过方法注入得到p层的实例的;

      但是使用方法注入的时候,要注意的就是,避免在依赖未注入的时候使用对象吧,但是构造方法就安全的多了没有这个担忧;

MVP架构的优缺点

  1. 优点:

    1. 结构清晰,划分职责清晰;
    2. 模块间解耦充分;
    3. 有利于组件的重用;
  2. 缺点:

    1. 有大量的接口;
    2. 代码结构会变得复杂;

MVVM

解决的问题

除了控制逻辑、数据处理逻辑、view交互的耦合之外,不仅解决了mvc中view 和 model耦合的问题;还解决了mvp中view 和 presenter 耦合的问题;

划分职责

  1. view: 显示UI
  2. viewmodel: 控制器,处理逻辑
  3. model :模型,数据的获取和储存;

不同职责如何通信

  1. 在mvvm中,解耦更彻底,当viewModel发生改变时,会自动通知view界面更新,当view有事件产生时,会自动反馈给viewModel;

  2. 流程就是:

    view产生了事件,自动更新给了viewModel,viewmodel进行逻辑处理之后,通知model数据加载或储存,然后把结果返回给viewmodel,viewmodel最后自动更新给了view;

MVVM的实现

这里主播是通过Livedata+viewmodel+databinding实现的,没学的可以学一下;

这里主播是实现了按钮点击+调用viewmodel的方法+调用Model的方法+回调至viewmodel+动态更新UI;

这里主播还想强调一下,主播看了一个人写的博客,里面写在Model层用viewmodel的实例的方法,主播写了后仍给ai, 结果ai说主播的是mvvm和mvp混合架构,主播很伤心;所以说大家如果想在Model里返回数据可以使用接口回调,标准的mvvm中Model不要过于有viewmodel的实例的;

view层:

java 复制代码
com.example.mvvm.Swy binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
得到viewmodel的实例,通过方法注入使得viewmodel可以调用Model层的方法;
BookViewModel bookViewModel = new ViewModelProvider(this).get(BookViewModel.class);
Model model = new Model();
bookViewModel.setMode(model);
将databinding和viewmodel联系,这样viewmodel中数据更新的时候会自动更新UI;
binding.setViewmodel(bookViewModel);
binding.setLifecycleOwner(this);

viewmodel层:

java 复制代码
public class BookViewModel extends ViewModel {
    private  MutableLiveData<Book> book  = new MutableLiveData<>(new Book("",""));
    private Model model;
    public MutableLiveData<Book> getBook(){
        return book;
    }
    public LiveData<Book> getsingleBook(){
        if(book == null){
            book = new MutableLiveData<>(new Book("",""));
        }
        return book;
    }

    public void setMode(Model mode) {
          this.model = (Model) mode;
    }

    public void getmes(View view) {
         Book book1  = book.getValue();
         String mes;
         Book finalBook = book1;

        model.getmes(book1.getId(), new Model.getmesmodel() {
             @Override
             public void getmesmothod(String s) {
                 finalBook.setName(s);
                book.setValue(finalBook);
             }
         });
    }


    public void clearmes(View view) {
        model.crearmes();
        book.setValue(new Book("",""));
    }
}

Model:

java 复制代码
public class Model {

     private Handler handler = new android.os.Handler(Looper.getMainLooper());

    public interface getmesmodel{
        void getmesmothod(String s);
    }

    public void getmes(String text,getmesmodel getmesmodel) {
        String mes;
        handler.post(new Runnable() {
            @Override
            public void run() {
                StringBuilder stringBuilder = new StringBuilder(text);;
                stringBuilder.append("喜欢李佳雪");
                getmesmodel.getmesmothod(stringBuilder.toString());
            }
        });

    }


    public void crearmes() {

    }
}

没啥好说的,大家看代码理解即可;

优缺点:

优点:
  1. 职责划分清晰;
  2. 模块间充分解耦;
  3. 在mvp基础上,把view和viewModel进行了充分解耦;
缺点:
  1. debug困难,由于view和vm解耦;难以看出view事件的传递;
  2. 复杂性加大;
相关推荐
Digitally1 小时前
如何通过蓝牙将联系人从 iPhone 传输到 Android
android·ios·iphone
t***p9352 小时前
业务架构、数据架构、应用架构和技术架构
架构
embrace993 小时前
【C语言学习】结构体详解
android·c语言·开发语言·数据结构·学习·算法·青少年编程
用户69371750013843 小时前
11.Kotlin 类:继承控制的关键 ——final 与 open 修饰符
android·后端·kotlin
用户0273851840263 小时前
【Android】LiveData的使用以及源码浅析
android·程序员
用户69371750013843 小时前
10.Kotlin 类:延迟初始化:lateinit 与 by lazy 的对决
android·后端·kotlin
G***E3163 小时前
PHP微服务通信消息队列实践
微服务·云原生·架构
稚辉君.MCA_P8_Java3 小时前
通义 Go 语言实现的插入排序(Insertion Sort)
数据结构·后端·算法·架构·golang
语落心生3 小时前
探秘新一代向量存储格式Lance-format (十三) 数据更新与 Schema 演化
架构