美文网首页Android开发技能知识点
谈谈Android框架 MVC、MVP、MVVM的区别

谈谈Android框架 MVC、MVP、MVVM的区别

作者: 黄海佳 | 来源:发表于2017-02-07 13:41 被阅读190次

    今天写写Android的MVC、MVP、MVVP三个框架的对比,并加深自己对这三个框架的理解。

    548b9bea8dc18.gif
    一 . MVC:Model-View-Controller

    MVC全名是:Model(模型) View(视图) Controller(控制器) 是软件[架构]中最常见的框架,简单来说,就是通过Controller的控制去操作Model层的数据,并且返回给View作展示。

    1.MVC的工作原理?
    Paste_Image.png
    1. View接受用户的交互请求。
    
    2. View将请求转交给Controller。
    
    3. Controller操作Model进行数据更新。
    
    4. 数据更新之后,Model通知View数据变化。
    
    5. View显示更新之后的数据。
    
    2.MVC优点?

    1)把业务逻辑全部分离到Controller中,模块化程度高。当业务逻辑变更的时候,不需要变更View和Model,只需要更换Controller就行了。
    2)须手动或通过观察者模式进行多视图更新。

    3.MVC缺点?

    1)Controller测试困难。Controller不知道任何View的细节,一个Controller能被多个View使用。
    2)View无法组件化,复用性较差。View是强依赖特定的Model的,如果需要把这个View抽出来作为一个另外一个应用程序可复用的组件就困难了,因为不同程序的的Model是不一样的。

    4.使用场景?
    适用于较小,功能较少,业务逻辑较少的项目。
    
    二 . MVP:Model-View-Presenter

    Presenter将Model的变化返回给View。和MVC不同的是,presenter会反作用于view,不像controller只会被动的接受view的指挥。正常情况下,发现可以抽象view,暴漏属性和事件,然后presenter引用view的抽象。这样可以很容易的构造view的mock对象,提高可单元测试性。在这里,presenter的责任变大了,不仅要操作数据,而且要更新view。
      在Passive View中,为了减少UI组件的行为,使用controller不仅控制用户事件的响应,而且将结果更新到view上。可以集中测试controller,减小view出问题的风险。

    1.MVP的工作原理?
    Paste_Image.png
    1.  View接受用户的交互请求
    
    2.  View将请求转交给Presenter
    
    3.  Presenter操作Model进行数据库更新
    
    4.  数据更新之后,Model通知Presenter数据发生变化
    
    5.  Presenter更新View的数据
    
    2.MVP优点?

    1.便于测试。
     Presenter对View是通过接口进行,在对Presenter进行不依赖UI环境的单元测试的时候。可以通过Mock一个 View对象,这个对象只需要实现了View的接口即可,单元测试的时候就可以完整的测试Presenter业务逻 辑的正确性。
     2.View可以进行组件化。
     在MVP当中,View不依赖Model。这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务逻辑完全无知。它只需要提供一系列接口提供给上层操作。
     3.View高度复用。
     4.解耦。

    3.MVP缺点?

    1.维护比较困难。
     Presenter中除了业务逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑,造成Presenter比较笨重,维护起来会比较困难。

    4.使用场景?
     视图界面不是很多的项目中。
    
    5 . 代码示例
    Paste_Image.png Paste_Image.png

    MainActivity

    public class MainActivity extends Activity implements IUserInfoShow {
    
        private static final String TAG = "MVP";
        private UserInfoPresenter mUserInfoPresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mUserInfoPresenter = new UserInfoPresenter(this, new GetUserInfoImpl());
            mUserInfoPresenter.getUserInfo(123);
        }
    
        @Override
        public void beforeLoding() {
            Log.i(TAG, "beforeLoding");
        }
    
        @Override
        public void getUserInfoSucceed(User user) {
            Log.i(TAG, "id:"+user.getId()+" realName:"+user.getRealName());
        }
    
        @Override
        public void getUserInfoFailed(String msg) {
            Log.i(TAG, "msg=" + msg);
        }
    
        @Override
        public void afterLoading() {
            Log.i(TAG, "afterLoading");
        }
    }
    

    User

    /**
     * @创建 HaiJia
     * @时间 2017/2/7 13:51
     * @描述 UserBean
     */
    
    public class User {
    
        private int id;//用户ID
        private String realName;//用户真实姓名
    
        public String getRealName() {
            return realName;
        }
    
        public void setRealName(String realName) {
            this.realName = realName;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    }
    

    IUserInfoShow

     public interface IUserInfoShow {
    
        void beforeLoding();
    
        void getUserInfoSucceed(User user);
    
        void getUserInfoFailed(String msg);
    
        void afterLoading();
    }
    
    // MainActivity extends Activity implements IUserInfoShow
    

    UserInfoPresenter

    public class UserInfoPresenter {
        private IGetUserInfo mIGetUserInfo;
        private IUserInfoShow mUserInfoShow;
    
        public UserInfoPresenter(IUserInfoShow mUserInfoShow, IGetUserInfo mIGetUserInfo) {
            this.mUserInfoShow = mUserInfoShow;
            this.mIGetUserInfo = mIGetUserInfo;
        }
    
        public void getUserInfo(int id){
            mUserInfoShow.beforeLoding();
            mIGetUserInfo.getUserInfo(id, new OnUserInfoListener() {
                @Override
                public void getUserInfoSuccess(User user) {
                    mUserInfoShow.getUserInfoSucceed(user);
                    mUserInfoShow.afterLoading();
                }
    
                @Override
                public void getUserInfoFailure(String msg) {
                    mUserInfoShow.getUserInfoFailed(msg);
                    mUserInfoShow.afterLoading();
                }
            });
        }
    }
    

    IGetUserInfo

    /**
     * @创建 HaiJia
     * @时间 2017/2/7 14:00
     * @描述 TODO
     */
    
    public interface IGetUserInfo {
        void getUserInfo(int id,OnUserInfoListener listener);
    }
    

    OnUserInfoListener

    /**
     * @创建 HaiJia
     * @时间 2017/2/7 14:01
     * @描述 TODO
     */
    
    public interface OnUserInfoListener {
        void getUserInfoSuccess(User user);
        void getUserInfoFailure(String msg);
    }
    

    GetUserInfoImpl

    /**
     * @创建 HaiJia
     * @时间 2017/2/7 14:03
     * @描述 实现类
     */
    
    public class GetUserInfoImpl implements IGetUserInfo {
    
        @Override
        public void getUserInfo(final int id, final OnUserInfoListener listener) {
            // 模拟数据
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (id == 123){
                        User user = new User();
                        user.setId(123);
                        user.setRealName("黄海佳");
                        listener.getUserInfoSuccess(user);
                    }else{
                        String msg = "用户数据出错,请回你的火星去";
                        listener.getUserInfoFailure(msg);
                    }
                }
            }).start();
        }
    }
    
    三 . MVVM:Model-View-ViewModel
    Paste_Image.png

    MVVM是在原有领域Model的基础上添加一个ViewModel,这个ViewModel除了正常的属性意外,还包括一些供View显示用的属性。例如在经典的MVP中,view有一个属性ischeck,需要在presenter中设置view的ischeck值。但是在MVVM中的presenter也会有一个ischeck属性来同步view的ischeck属性,可能会用到observer模式同步ischeck的值。在MVVM中,presenter被改名为ViewModel,就演变成了你看到的MVVM。在支持双向绑定的平台,MVVM更受欢迎。例如:微软的WPF和Silverlight。

    1.MVVM优点?

    1.提高可维护性。
     解决了MVP大量的手动View和Model同步的问题,提供双向绑定机制。提高了代码的可维护性。
     2.简化测试。
     因为同步逻辑是交由Binder做的,View跟着Model同时变更,所以只需要保证Model的正确性,View就正确。大大减少了对View同步更新的测试。
     3.ViewModle易于单元测试。

    2.使用场景?
     适用于界面展示的数据较多的项目。
    
    3.代码示例
    Paste_Image.png

    在Module的build.gradle中添加下面代码,注意的是保证Gradle插件版本不低于1.5.0-alpha1

    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.2"
        ...
        dataBinding {
            enabled true//添加这个
        }
    }
    

    activity_main

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
    
            <import type="com.haijia.mvvp.bean.User" />
    
            <variable
                name="user"
                type="User" />
    
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{String.valueOf(user.id)}" />
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{user.realName}" />
    
    
        </LinearLayout>
    
    </layout>
    
    

    MainActivity

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            binding.setUser(new User(123,"黄海佳"));
        }
    }
    

    就是这么简单就搞定了MVVM的框架,但是这里面有很多细节,下一篇文章在详细介绍一下data binding框架。

    参考

    如何更高效的使用MVP以及官方MVP架构解析

    一个Android项目搞定所有主流架构-2.MVP+单元测试

    浅谈Android MVP设计模式(简单结合RxJava+Retrofit)

    RxJava 与 Retrofit 结合的最佳实践

    相关文章

      网友评论

        本文标题:谈谈Android框架 MVC、MVP、MVVM的区别

        本文链接:https://www.haomeiwen.com/subject/rempittx.html