美文网首页
Android中MVC、MVP和MVVM

Android中MVC、MVP和MVVM

作者: AndroidHint | 来源:发表于2018-06-13 01:24 被阅读0次

    画出这三种开发模式的设计图,并给出它们的适用场景和优缺点。

    一、MVC

    1、MVC简介

    MVC是Model View Controller的缩写,是一种典型的设计开发模式。其中Model为模型,View为视图,Controller为控制器。它的模式设计图如下所示:


    MVC开发模式设计图

    它的工作流程是这样的:
    View接收用户的请求操作
    View将用户的请求操作传递给Controller
    Controller操作Model进行数据的更新
    Mode在数据更新完毕后通知View进行界面刷新

    从上面的工作流程可以得知,Controller持有了View和Model对象,Model持有View对象。

    在Android中,View对应着xml布局文件,Model对应着实体模型(网络、数据库、IO等),Controller对应着Activity的业务处理,数据处理,UI展示等逻辑。在实际开发过程中,xml作为View层,能够实现的功能实在是太弱,所以一般我们会将Activity作为View和Controller。

    2、MVC的一个例子

    我们通过一个例子来看一下MVC模式的工作流程:


    现在我们要点击上面“寻找图书”的按钮,然后在下面可以得到图书信息。上图就是xml的布局。

    我们先看一下Model层:

    package com.example.runningh.mydemo.testmvc;
    
    
    /**
     * Created by hwldzh on 2018/6/12
     * 类描述: Model层
     */
    public class Book {
        private SearchBookActivity activity;
    
        private int price = 100;
    
        private String bookName = "Android艺术开发探索";
    
        public Book(SearchBookActivity activity) {
            this.activity = activity;
        }
    
        public void findBook() {
            activity.updateView(this);
        }
    
        public String toString() {
            return "bookName=" + bookName + "; bookPrice=" + price;
        }
    }
    

    Controller层:

    package com.example.runningh.mydemo.testmvc;
    
    
    /**
     * Created by hwldzh on 2018/6/12
     * 类描述: Controller层
     */
    public class ControllerBook {
        private SearchBookActivity activity;
    
        public ControllerBook(SearchBookActivity activity) {
            this.activity = activity;
        }
    
        public void findBook() {
            Book book = new Book(activity);
            book.findBook();
        }
    }
    

    View层:

    package com.example.runningh.mydemo.testmvc;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.view.View;
    import android.widget.TextView;
    
    import com.example.runningh.mydemo.R;
    
    /**
     * Created by hwldzh on 2018/6/12
     * 类描述: View层
     */
    public class SearchBookActivity extends Activity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.search_book);
    
            final ControllerBook controllerBook = new ControllerBook(this);
            findViewById(R.id.find_books).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    controllerBook.findBook();
                }
            });
        }
    
        public void updateView(Book book) {
            TextView bookInfoView = findViewById(R.id.book_info_view);
            bookInfoView.setText(getString(R.string.book_info, book.toString()));
        }
    }
    

    可以看到在View层中(SearchBookActivity)通过按钮的点击事件,触发Controller层(ControllerBook)的findBook方法,在Controller层的findBook方法中调用了Model层(Book)的findBook方法,在Model层获得Book数据后,将该数据传递给View层(通过调用SearchBookActivity的updateView方法),然后在updateView方法中对View进行更新。

    3、优缺点

    • 优点:
      模块化的程度很高,各层负责完成不同的逻辑处理。
    • 缺点:
      在Android实际开发中,MVC开发模式中的Activity既要负责View层的更新,同时也负责Controller层对逻辑的控制,如果一个功能比较复杂,那么Activity要承担的任务就非常繁重,导致Activity的代码量非常庞大。
      Mode层和View层之间存在着耦合关系。

    4、适用场景

    由上面MVC的优缺点可以得知,MVC开发模式适合运用在一些功能比较简单的,业务逻辑比较少的小型项目中。

    二、MVP

    1、MVP简介

    MVP是Model View Presenter的缩写。其中Model为模型,ViewWie视图,Presenter为桥接器。针对MVC设计模式中Activity的工作量巨大,代码逻辑比较复杂等缺点进行了一定的改进,将代码控制逻辑单独拆分开,放在Presenter模块。它的模式设计图如下所示:


    MVP开发模式设计图

    它的工作流程是这样的:
    View接收用户的请求操作
    View将用户的请求操作传递给Presenter
    Presenter操作Model进行数据的更新
    Model在数据更新完毕后回调给Presenter
    Presenter在拿到更新的数据后将数据回调给View
    View进行界面的刷新

    在Android中,View对应着xml布局文件和Activity,Model对应着实体模型(网络、数据库、IO等),Presenter作为View和Model两者之间的桥梁,对业务逻辑进行操控,这样就将View和Model进行了解耦,它们两者都由Presenter进行逻辑之间的操控。

    2、MVP的一个例子

    还是上面的例子,我们将其修改为MVP模式。
    我们先看一下Model层:

    package com.example.runningh.mydemo.testmvc;
    
    
    /**
     * Created by hwldzh on 2018/6/12
     * 类描述: Model层
     */
    public class Book {
        private OnFindBookListener mListener;
    
        private int price = 100;
    
        private String bookName = "Android艺术开发探索";
    
        public Book(OnFindBookListener listener) {
            this.mListener = listener;
        }
    
        public void findBook() {
            String bookInfo = "bookName=" + bookName + "; bookPrice=" + price;
            mListener.onSuccess(bookInfo);
        }
    
        public interface OnFindBookListener {
            void onSuccess(String bookInfo);
        }
    }
    

    可以看到Model不再持有Activity的引用,而是新增了一个回调方法,当获取到数据后,调用该回调方法,该回调方法在Presenter层中实现。下面我们看一下Presenter层:

    package com.example.runningh.mydemo.testmvc;
    
    
    /**
     * Created by hwldzh on 2018/6/12
     * 类描述: Presenter层
     */
    public class PresenterBook {
        private SearchBookActivity activity;
    
        public PresenterBook(SearchBookActivity activity) {
            this.activity = activity;
        }
    
        public void findBook() {
            Book book = new Book(new Book.OnFindBookListener() {
                @Override
                public void onSuccess(String bookInfo) {
                    activity.updateView(bookInfo);
                }
            });
            book.findBook();
        }
    }
    

    Presenter层调用了Model层的findBook方法获取数据,并实现了获取数据后的回调方法,在回调方法中调用Activity的updateView方法通知Activity去刷新界面。Activity单独作为View层,和上面MVC的变化不大,我们看一下Activity作为的View层的代码逻辑:

    package com.example.runningh.mydemo.testmvc;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.view.View;
    import android.widget.TextView;
    
    import com.example.runningh.mydemo.R;
    
    /**
     * Created by hwldzh on 2018/6/12
     * 类描述: View层
     */
    public class SearchBookActivity extends Activity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.search_book);
    
            final PresenterBook presenterBook = new PresenterBook(this);
            findViewById(R.id.find_books).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    presenterBook.findBook();
                }
            });
        }
    
        public void updateView(String bookInfo) {
            TextView bookInfoView = findViewById(R.id.book_info_view);
            bookInfoView.setText(getString(R.string.book_info, bookInfo));
        }
    }
    

    3、优缺点

    • 优点:
      Model和View完全分离开,两者之间没有任何耦合,两者的修改互不影响。
      Presenter可以作用于多个View,可以将公共的逻辑放在BasePresenter中,子类Presenter做一些和View相关的逻辑。
      将逻辑放在Presenter中,可以脱离用户接口来测试这些逻辑(单元测试)。
    • 缺点:
      Presenter持有了Model和View的引用,其中包含了大量的控制逻辑,使得Presenter变得复杂而庞大,后期维护会比较困难。

    4、适用场景

    从MVP的优缺点可以得知每一个Presenter会和一个View对应起来,所以MVP适用于View不是很多的中型项目。

    三、MVVM

    1、MVVM简介

    MVVM是Model View ViewModel的缩写。其中Model为模型,View为视图,ViewModel为View的数据模型和Presenter的合体,其实就是将MVP中的Presenter替换成了ViewModel,并通过双向数据绑定来实现View和ViewModel的交互。而在Android中一般使用Data Binding来实现双向的数据绑定。它的模式设计图如下所示:


    MVVM开发设计图

    它的工作流程和MVP模式差不多是一样的,只是将Presenter换成了ViewModel,并且将Presenter和View的交互方式用data-binding来进行代替。

    在Android中,View对应着xml布局文件和Activity,Model对应着实体模型(网络、数据库、IO等),ViewModel作为View和Model两者之间的桥梁,除了兼具Presenter的功能外,它和View的交互使用了data-binding,使得View和ViewModel之间的耦合进一步降低。

    2、MVVM的一个例子

    要实现data-binding,我们需要在app下的gradle文件中进行如下配置:

    android {
        ...
        dataBinding {
            enabled = true
        }
        ...
    }
    

    继续使用上面那个例子,我们将MVP中的Presenter去掉,并写一个ViewModel对象,如下所示:

    package com.example.runningh.mydemo.testmvc;
    
    import android.databinding.BaseObservable;
    import android.view.View;
    
    
    /**
     * Created by hwldzh on 2018/6/13
     * 类描述: ViewModel层
     */
    public class ViewModelBook extends BaseObservable {
        public String bookInfo;
        public View.OnClickListener btnListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                findBook();
            }
        };
    
        public String getBookInfo() {
            return bookInfo;
        }
    
        public void setBookInfo(String bookInfo) {
            this.bookInfo = bookInfo;
            notifyChange();
        }
    
        public View.OnClickListener getBtnListener() {
            return btnListener;
        }
    
        public void setBtnListener(View.OnClickListener btnListener) {
            this.btnListener = btnListener;
        }
    
        private void findBook() {
            Book book = new Book(new Book.OnFindBookListener() {
                @Override
                public void onSuccess(String bookInfo) {
                    setBookInfo(bookInfo);
                }
            });
            book.findBook();
        }
    }
    

    可以看到ViewModel必须继承BaseObservable类,其中bookInfo是返回的图书信息,btnListener是点击按钮触发的事件。对于bookInfo和btnListener是要和View进行数据绑定的,所以在数据返回后,需要调用notifyChange方法。我们看一下View层的xml布局:

    <?xml version="1.0" encoding="utf-8"?>
    <layout
        xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
            <variable
                name="searchBook"
                type="com.example.runningh.mydemo.testmvc.ViewModelBook" />
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
        <Button
            android:id="@+id/find_books"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{searchBook.btnListener}"
            android:text="寻找图书"/>
    
        <TextView
            android:id="@+id/book_info_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@{searchBook.bookInfo}"/>
        </LinearLayout>
    </layout>
    

    再看View(Activity)的实现:

    package com.example.runningh.mydemo.testmvc;
    
    import android.app.Activity;
    import android.databinding.DataBindingUtil;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    
    import com.example.runningh.mydemo.R;
    import com.example.runningh.mydemo.databinding.SearchBooksBinding;
    
    /**
     * Created by hwldzh on 2018/6/12
     * 类描述: View层
     */
    public class SearchBookActivity extends Activity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //SearchBookBinding类是由search_books布局自动生成
            SearchBooksBinding binding = DataBindingUtil.setContentView(this, R.layout.search_books); 
            binding.setSearchBook(new ViewModelBook()); //setSearchBook方法是由search_books布局自动生成
        }
    }
    

    3、优缺点

    • 优点:
      View和ViewModel之间的耦合度进一步降低,一个ViewModel可以绑定到不同的View上。
      可重用性提高,可以将一些视图逻辑放在一个ViewModel中,让很多View重用这段视图逻辑。

    • 缺点:
      代码中的bug比较难发现,界面异常可能是View的问题,也可能是Model的问题,数据绑定使得该问题很难被发现。
      数据双向绑定不利于代码重用。数据绑定让一个View和一个Model绑定起来,不同模块的Model基本上是不同的,这就是不能简单的重用View了。

    4、适用场景

    MVVM的开发模式适用于界面展示比较复杂,并且经常需要动态更新的项目。

    相关文章

      网友评论

          本文标题:Android中MVC、MVP和MVVM

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