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

一、MVC

1、MVC简介

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



ANDROID MVC代码下载 android中的mvc模式_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模式的工作流程:



ANDROID MVC代码下载 android中的mvc模式_mvc_02

现在我们要点击上面“寻找图书”的按钮,然后在下面可以得到图书信息。上图就是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 voidfindBook() {
        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模块。它的模式设计图如下所示:



ANDROID MVC代码下载 android中的mvc模式_android_03

它的工作流程是这样的: 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 voidfindBook() {
        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来实现双向的数据绑定。它的模式设计图如下所示:



ANDROID MVC代码下载 android中的mvc模式_mvc_04

它的工作流程和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的开发模式适用于界面展示比较复杂,并且经常需要动态更新的项目。