• Mvc、Mvp和Mvvm


    一.概念

    1.框架模式和设计模式

    • 简单理解,框架面向一系列相同行为代码的重用,而设计模式面对的是一系列相同结构代码的重用;
    • 软件开发领域三种级别的重用
      • 内部重用,在同一应用中能公共使用的抽象块;
      • 代码重用,通用模块组合成库或工具类,及在多个应用和领域中都能重用;
      • 应用框架的重用,专用领域提供通用的或现成的基础结构,以获得最高级别的重用性;

    二.Mvc

    1.全称:Model–View–Controller

    • 模型(Model)-视图(View)-控制器(Controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界
      面显示分离的方法组织代码;
    • 视图层(View)
      • 对应于Xml布局文件和Java代码动态View部分;
    • 控制层(Controller)
      • MVC中Android的控制层是由Activity来承担的;
      • Activity本来主要是作为初始化页面,展示数据的操作,但是因为XML视图功能太弱,所以Activity既要负责视图的显示又要加入控制逻辑,承担的功能过多;
    • 模型层(Model)
      • 针对业务模型,建立的数据结构和相关的类,它主要负责网络请求,数据库处理,I/O的操作;
    • 通信方式(所有通信都是单向的)
      • View 传送指令到 Controller;
      • Controller 完成业务逻辑后,要求 Model 改变状态;
      • Model 将新的数据发送到 View,用户得到反馈;

    2.mvc在android中的代码实现

    2.1.BaseModel,所有业务逻辑model的父类

    public interface BaseModel {
        //用于跟activity或者fragment生命周期同步,在destroy做一些销毁操作
        void onDestroy();
    }
    
    • 1
    • 2
    • 3
    • 4

    2.2.Callback:根据View或者Controller调用Model时回调的参数个数选择使用

    public interface Callback1<T> {
        void onCallBack(T t);
    }
    public interface Callback2<T,P> {
        void onCallBack(T t,P p);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.3.具体的SampleModel

    public class SampleModel  implements BaseModel{
    
        public void  getUserInfo(String uid,Callback1<UserInfo> callback)
        {
    
            UserInfo userInfo= new HttpUtil<UserInfo>().get(uid);
            callback.onCallBack(userInfo);
    
        }
    
        @Override
        public void onDestroy() {
    
        }
    
        public class UserInfo
        {
            private int age;
            private String name;
    
            public int getAge() {
                return age;
            }
    
            public void setAge(int age) {
                this.age = age;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2.4.SampleActivity:充当View和Controller

    public class SampleActivity extends AppCompatActivity {
        private SampleModel sampleModel;
        Button button;
        EditText textView;
        TextView tvAge,tvName;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_sample);
            sampleModel=new SampleModel();
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    getUserInfo(textView.getText().toString());
                }
            });
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            sampleModel.onDestroy();
        }
    
        /**
         * 获取用户信息
         * @param uid
         */
        private void getUserInfo(String uid)
        {
            sampleModel.getUserInfo(uid, new Callback1<SampleModel.UserInfo>() {
                @Override
                public void onCallBack(SampleModel.UserInfo userInfo) {
                    setDataToView(userInfo);
                }
            });
        }
    
        /**
         * 设置用户信息到view
         */
        private void setDataToView(SampleModel.UserInfo userInfo)
        {
            tvAge.setText(userInfo.getAge());
            tvName.setText(userInfo.getName());
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    3.Mvc总结

    • 3.1.控制器Activity
      • 主要起到的作用就是解耦,将视图View和Model进行分离;
      • View和Model在Activity中进行绑定或完成其它逻辑;
    • 3.2.优点
      视图View和Model进行分离,降低耦合度;
    • 3.3.缺点
      • Activity类过于臃肿;
      • View 无法组件化。View 是强依赖特定的 Model 的,如果需要把View 抽出来作为一个另外一个应用程序可复用的组件就困难了;

    二.Mvp

    1.特点

    • MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向;
    • 各部分之间的通信,都是双向的;
    • View 与 Model 不发生联系,都通过 Presenter 传递;
    • View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里;

    2.Mvp代码示例

    2.1.BasePresenter:类似于MVC中的BaseModel

    public interface BasePresenter {
        void onDestroy();
    }
    
    • 1
    • 2
    • 3

    2.2.BaseView:是所有View的父类

    • 将android中的view抽象化出来,只有跟view相关的操作都由baseView的实现类去完成。
    public interface BaseView<P extends BasePresenter> {
        void setPresenter(P presenter);
    }
    
    • 1
    • 2
    • 3

    2.3.Contract 契约类

    • 用于定义同一个界面的view的接口和presenter的具体实现。
    • 好处是通过规范的方法命名和注释可以清晰的看到整个页面的逻辑。
    public class SampleContract {
        public static class Presenter implements BasePresenter
        {
            public void  getUserInfo(String uid,Callback1<SampleModel.UserInfo> callback)
            {
                SampleModel.UserInfo userInfo= new HttpUtil<SampleModel.UserInfo>().get(uid);
                callback.onCallBack(userInfo);
            }
    
            @Override
            public void onDestroy() {
    
            }
        }
        public interface View extends BaseView<Presenter>
        {
             void setDataToView(SampleModel.UserInfo userInfo);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.4.SampleActivity

    • SampleActivity实现了SampleContract.View只是作为View存在的
    public class SampleActivity extends AppCompatActivity implements SampleContract.View{
        private  SampleContract.Presenter mPresenter;
        Button button;
        EditText textView;
        TextView tvAge,tvName;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_sample);
            setPresenter(new SampleContract.Presenter());
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mPresenter.getUserInfo(textView.getText().toString(), new Callback1<SampleModel.UserInfo>() {
                        @Override
                        public void onCallBack(SampleModel.UserInfo userInfo) {
                            setDataToView(userInfo);
                        }
                    });
                }
            });
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mPresenter.onDestroy();
        }
    
        @Override
        public void setDataToView(SampleModel.UserInfo userInfo) {
            tvAge.setText(userInfo.getAge());
            tvName.setText(userInfo.getName());
        }
    
    
        @Override
        public void setPresenter(SampleContract.Presenter presenter) {
            mPresenter=presenter;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    3.Mvp总结

    • 通过引入接口BaseView,让相应的视图组件如Activity,Fragment去实现BaseView,实现了视图层的独立;
    • 通过中间层Preseter实现了Model和View的完全解耦;
    • 优点
      • mvp解决了mvc的Controller和View很难做到完全解耦的问题;
      • View 可以进行组件化。在 MVP 当中,View 不依赖 Model。这样就可以让 View 从特定的业务场景中脱
        离出来,可以说 View 可以做到对业务逻辑完全无知。它只需要提供一系列接口提供给上层操作。这样就可
        以做高度可复用的 View 组件;
    • 缺点
      随着业务逻辑的增加,一个页面可能会非常复杂,UI的改变是非常多,会有非常多的case,这样就会造成View的接口会很庞大。

    三.Mvvm

    • MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致;
    • 唯一的区别是,它采用双向绑定(Mvvm的核心data-binding):View的变动,自动反映在 ViewModel,反之亦然;
    • mvp中随着业务逻辑的增加,UI的改变多的情况下,会有非常多的跟UI相关的case,这样就会造成View的接口会很庞大。 mvvm解决了mvp的这个问题,通过双向绑定的机制,实现数据和UI内容,只要想改其中一方,另一方都能够及时更新的一种设计理念,这样就省去了很多在View层中写很多case的情况,只需要改变数据就行;
    • Activity和xml layout充当View,ViewModel处理业务逻辑以及获取数据,弱化Model;

    1.代码示例

    1.1.BaseViewModel

    • ViewMode层主要处理业务逻辑和获取数据,mViewDataBinding是通过View层传递过来。
    public interface BaseViewModel {
        void onDestroy();
    }
    
    public abstract class AbstractViewModel<T extends ViewDataBinding> implements BaseViewModel {
        public T mViewDataBinding;
        public AbstractViewModel(T viewDataBinding)
        {
            this.mViewDataBinding=viewDataBinding;
        }
    
        @Override
        public void onDestroy() {
            mViewDataBinding.unbind();
        }
    }
    
    public class SampleViewModel extends AbstractViewModel<ActivitySampleMvvmBinding> {
    
        public SampleViewModel(ActivitySampleMvvmBinding viewDataBinding) {
            super(viewDataBinding);
        }
    
        public  void getUserInfo(String uid, Callback1<SampleModel.UserInfo> callback)
        {
            //从网络或缓存获取信息
            SampleModel.UserInfo userInfo=new SampleModel.UserInfo();
            userInfo.setName("tom");
            userInfo.setAge(18);
            callback.onCallBack(userInfo);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2.Mvvm总结

    • 解决MVP中View层好多接口的问题,让View变得更简洁;
    • View的变动,自动反映在 ViewModel,反之亦然;
    • 看起来MVVM很好的解决了MVC和MVP的不足,但是由于数据和视图的双向绑定,导致出现问题时不太好定位来源,有可能数据问题导致,也有可能业务逻辑中对视图属性的修改导致。如果项目中打算用MVVM的话可以考虑使用官方的架构组件ViewModel、LiveData、DataBinding去实现MVVM(项目中已经使用,至今有一年多,待,待改善、整理到开源项目中);
    • 优点
      • 提高可维护性。解决了 MVP 大量的手动 View 和 Model同步的问题,提供双向绑定机制。提高了代码的可维护性;
      • 简化测试。mvp中View与Model的同步是交给Presenter去做的,在mvvm中,不需要手动去完成,交由databinding实现。Model变化,View会跟着Model同时变更,所以只需要保证Model的正确性,View就正确。大大减少了对 View 同步更新的测试;
    • 缺点
      • 过于简单的图形界面不适用,或说牛刀杀鸡;
      • 对于大型的图形应用程序,视图状态较多,ViewModel的构建和维护的成本都会比较高;
      • 数据绑定的声明是指令式地写在 View 的模版当中的,这些内容是没办法去打断点 debug 的;

    四.Mvc/Mvp/Mvvm比较

    • Mvp不是一个标准化的模式,它有很多种实现方式,可以根据自己的需求或者认为对的方式去修正Mvp的实现方式,可以随Presenter的复杂程度变化。只要保证是通过Presenter将View和Model解耦;
    • 通过以上可以看出,Mvc的耦合度还是相对较高,View可以直接访问Model,导致三者之间形成回路;
    • Mvc与Mvp的主要区别:Mvp的View不能直接访问Model,需要通过Presenter发出请求,View与Model不直接通信;
    • Mvp和Mvvm的结构非常相似,唯一的区别是View和Model进行双向绑定,两者有一方变化会反应到另一方上。而Mvp和Mvvm的主要区别是Mvp的View更新需要通过Presenter,而Mvvm不需要;

    五.总结

    • 项目如果简单,维护性不高,将模块封装好,不需要采用什么架构和设计模式,只需要将每个模块封装好,方便调用即可,不要为了使用设计模式或架构方法而使用;
    • 小型项目可以采用Mvc;
    • 侧重于数据展示和交互(对于偏向展示型的App,绝大多数业务逻辑都在后端,App主要功能就是展示数据,交互等),建议采用Mvvm;
    • 大型项目,业务复杂的采用Mvp;
    • 对于工具类或者需要写很多业务逻辑App,Mvp或者Mvvm都可,可根据具体的项目灵活的对架构进行选择(如:混合架构)等;

    六.参考

  • 相关阅读:
    原型模式的学习
    SpringCloud集成LoadBalance,负载均衡
    C#毕业设计——基于C#+asp.net+sqlserver作业提交系统设计与实现(毕业论文+程序源码)——作业提交系统
    服务器数据恢复-EVA存储多块硬盘磁头和盘片损坏离线的数据恢复案例
    堆排序+TOPK问题
    【React】01-React的入门
    启明智显分享|4.3寸智能串口屏应用于充电桩
    GPT4 Advanced data analysis Code Interpreter 做行业数据分析、可视化处理图像、视频、音频等
    Pr:基本图形(文本)
    rename 批量修改文件名简单用法
  • 原文地址:https://blog.csdn.net/itTalmud/article/details/126146755