MVC MVP MVVM总结

MVC

在这里插入图片描述
MVC 模式(Model–view–controller)是软件工程中的一种软件架构模式,它把软件系统分为三个基本部分:模型(Model)、视图(View)控制器(Controller)

组成部分

模型(Model):业务逻辑部分,具体的算法逻辑在这一部分中。
视图(View):UI组件,在Android中就是TextView、Button、Activity等组件。
控制器(Controller):View层收到的用户请求转发给控制器,控制器通知模型进行具体的操作。

请求流程

  1. 用户通过View层发出请求
  2. Controller接收请求
  3. Controller操作Model进行逻辑处理
  4. Model处理完后通知View更新数据(通常是通过回调)
  5. View现实更新的数据

举个例子

写个登录功能的例子吧,两个TextView、一个Button。

项目结构图
在这里插入图片描述
Model层
ILoginModel

// 一个接口,里面有一个方法,Model的实现类给出具体实现。
public interface ILoginModel {
    void login(String account,String password);
}

ILoginModelImp

public class LoginModelImp implements ILoginModel { //实现ILoginModel接口,给出login方法的具体实现
    private LoginCallBack mLoginCallBack;	

    public LoginModelImp(LoginCallBack mLoginCallBack) {
        this.mLoginCallBack = mLoginCallBack;
    }

    @Override
    public void login(String account, String password) {
        if (TextUtils.isEmpty(account) || TextUtils.isEmpty(password)) {
            if (mLoginCallBack != null)
                mLoginCallBack.onFailed("账号或密码不能为空");
        } else if (password.equals("12345678")) {
            if (mLoginCallBack != null)
                mLoginCallBack.onSucceed();
        } else {
            if (mLoginCallBack != null)
                mLoginCallBack.onFailed("密码错误");
        }
    }

	//回调接口,Model层处理完逻辑后回调,通知View更新数据。
    public interface LoginCallBack {
        void onSucceed();
        void onFailed(String tips);
    }
}

View层(Controller)
MVCActivity

public class MVCActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText mAccount, mPassword;
    private Button mLogin;
    // 持有一个Model的成员变量
    private ILoginModel mLoginModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvc);

        init();
        mLogin.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.mvc_btn_login:
                String accountText = mAccount.getText().toString();
                String passwordText = mPassword.getText().toString();
                // 调用Model层的login方法
                mLoginModel.login(accountText, passwordText);
                break;
        }
    }

    private void init() {
        mAccount = findViewById(R.id.mvc_ed_account);
        mPassword = findViewById(R.id.mvc_ed_password);
        mLogin = findViewById(R.id.mvc_btn_login);
        // 初始化Model变量,并传入回调接口
        mLoginModel = new LoginModelImp(new LoginModelImp.LoginCallBack() {
            @Override
            public void onSucceed() { // 成功则显示登录成功
                Toast.makeText(MVCActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailed(String tips) { // 失败则显示错误信息
                Toast.makeText(MVCActivity.this, tips, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

在这个例子中,用户点击登录按钮后,在onClik方法中会调用Model层的login方法,Model在判断账号密码是否正确后,通过回调通知View层,View再显示出登录结果。

优点

1.在大型项目中使项目结构更加清晰
2.降低了View和Model的耦合性

缺点

1.在Android中Controller和View不能彻底分离,Controller和View都在Activity中,当业务需求不断增长,Activity的代码会变得庞大臃肿。
2.Controller和View不能彻底分离,意味着View层和Model层还存在比较高的耦合度。

MVP

在这里插入图片描述
MVP和MVC最大的区别就是,在MVP中,View和Model彻底解耦,View和Model不再通信,而是通过Presenter(相当于桥梁)。

请求流程

1.用户通过View发出请求
2.Presenter接收用户请求
3.Presenter通知Model进行逻辑处理
4.Model处理完成后通过回调告诉Presenter
5.Presenter通知View更新数据
6.View显示更新的数据

还是那个例子

项目结构
在这里插入图片描述
Model层跟MVC中的一样

Presenter层
IPresenter

public interface IPresenter {
    void login(String account,String password);
}

Presenter

public class Presenter implements IPresenter {
	// 同时持有View、Model的成员变量,因为View与Model的通信是通过Presenter来进行的
    private IView mView;
    private ILoginModel mLoginModel;

    public Presenter(IView view) {
        this.mView = view;
        mLoginModel = new LoginModelImp(new LoginModelImp.LoginCallBack() {
        	// 回调中通知View更新UI
            @Override
            public void onSucceed() {
                mView.showText("登录成功");
            }

            @Override
            public void onFailed(String tips) {
                mView.showText(tips);
            }
        });
    }

    @Override
    public void login(String account, String password) {
    	// 调用Model的login
        mLoginModel.login(account, password);
    }
}

View层
IView

// 通过一个接口定义View层所有更新UI的操作
public interface IView {
    void showText(String text);
}

MVPActivity

public class MVPActivity extends AppCompatActivity implements IView, View.OnClickListener {
    private EditText mAccount, mPassword;
    private Button mLogin;
    // 持有Presenter的成员变量,把用户请求转发到此presenter中
    private IPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvp);

        init();
        mLogin.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.mvp_btn_login:
                String accountText = mAccount.getText().toString();
                String passwordText = mPassword.getText().toString();
                // 转发用户请求到presenter
                mPresenter.login(accountText, passwordText);
                break;
            default:
                break;
        }
    }

    @Override
    public void showText(String text) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }

    private void init() {
        mAccount = findViewById(R.id.mvp_ed_account);
        mPassword = findViewById(R.id.mvp_ed_password);
        mLogin = findViewById(R.id.mvp_btn_login);
        mPresenter = new Presenter(this);
    }
}

优点

1)复杂的逻辑处理放在presenter进行处理,减少了activity的臃肿。
2)M层与V层完全分离,修改V层不会影响M层,降低了耦合性。
3)P层与V层的交互是通过接口来进行的,便于单元测试。

缺点

1)每个view都有presenter ,类相对比较多。

MVVM

Model-View-ViewModel
在这里插入图片描述
MVP的升级版,流程与MVP类似,但引入了Data Binding技术,实现View和ViewModel数据的双向绑定,进一步降低View和ViewModel的耦合度,减轻Activity的压力。

继续那个例子

DataBinding的用法大家可以自行上网查阅学习(笔者也是第一次用,不好介绍),这里把重点放在MVVM这个模式上。
项目结构图
在这里插入图片描述
Model层还是和前面的一样

ViewModel
这里ViewModel因为要和View绑定数据,所以有mAccount、mPassword、mOnClickListener,这些变量都跟View层的组件绑定在一起。除了这些外,剩下的代码和MVP中的Presenter类似。
LoginViewModel

// BaseObservable是databinding中的,当数据变更时,可以使用notify等方法通知View(这里例子没有用到)
public class LoginViewModel extends BaseObservable {
    private IView mView;
    private ILoginModel mLoginModel;
    private String mAccount;
    private String mPassword;
    private View.OnClickListener mOnClickListener;

    public String getAccount() {
        return mAccount;
    }

    public String getPassword() {
        return mPassword;
    }

    public void setAccount(String mAccount) {
        this.mAccount = mAccount;
    }

    public void setPassword(String mPassword) {
        this.mPassword = mPassword;
    }

    public View.OnClickListener getOnClickListener() {
        return mOnClickListener;
    }

    public LoginViewModel(IView view, String mAccount, String mPassword) {
        this.mView = view;
        mLoginModel = new LoginModelImp(new LoginModelImp.LoginCallBack() {
            @Override
            public void onSucceed(String tips) {
                mView.showText(tips);
            }

            @Override
            public void onFailed(String tips) {
                mView.showText(tips);
            }
        });
        mOnClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                login();
            }
        };
        this.mAccount = mAccount;
        this.mPassword = mPassword;
    }

    public void login() {
        mLoginModel.login(mAccount, mPassword);
    }
}

View层
使用databinding的xml文件和普通的不一样,先看一下。
activity_mvvm.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewmodel"
            type="com.example.mvdemo.mvvm.viewmodel.LoginViewModel" />
        <variable
            name="presenter"
            type="com.example.mvdemo.mvvm.view.MVVMActivity.Presenter" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onTextChanged="@{presenter.onTextChanged1}"
            android:text="@{viewmodel.account}" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onTextChanged="@{presenter.onTextChanged2}"
            android:text="@{viewmodel.password}" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{presenter.onClick}"
            android:text="@string/btn_login_text" />
    </LinearLayout>

</layout>

IView跟MVP的一样
MVVMActivity

package com.example.mvdemo.mvvm.view;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;

import com.example.mvdemo.R;
import com.example.mvdemo.databinding.ActivityMvvmBinding;
import com.example.mvdemo.mvvm.viewmodel.LoginViewModel;

public class MVVMActivity extends AppCompatActivity implements IView {
    private ActivityMvvmBinding mBinding;
    private LoginViewModel mLoginViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
        mLoginViewModel = new LoginViewModel(this, "", "");
        mBinding.setViewmodel(mLoginViewModel);
        mBinding.setPresenter(new Presenter());
    }

    public class Presenter {
        public void onTextChanged1(CharSequence s, int start, int before, int count) {
            mLoginViewModel.setAccount(s.toString());
        }
        public void onTextChanged2(CharSequence s, int start, int before, int count) {
            mLoginViewModel.setPassword(s.toString());
        }
        public void onClick(View view) {
            mLoginViewModel.login();
        }
    }

    @Override
    public void showText(String text) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }
}

注意这里的Presenter跟MVP中的不是同一个东西,这里的Presenter只是一个内部类,是提供给组件绑定事件用的;而MVP中的Presenter是一个层面。可以看到使用databinding技术的Activity非常简洁,没有了那些findViewById等代码,其他的跟MVP模式类似。而像ActivityMvvmBinding这些类是系统自动生成的,并不是自己创建的。

优点

1)引入Data Binding技术后,Activity减少了很多冗余的代码,如findViewById等,使得Activity的代码非常简洁。
2)双向绑定时,当Model变化时,View-Model会自动更新,View也会自动变化。

缺点

1)数据绑定使得 Bug 很难被调试。
2)数据双向绑定不利于代码重用。

总结

其实MV+X模式的目的都是解耦,把View和Model分离,View层只负责更新UI,Model层负责具体的算法逻辑、耗时操作等。值得注意的是,不能为了用模式而使用模式,模式并不能简化我们的系统,甚至可能使系统更加难以理解(多了很多的接口),但在大型项目,这些代价换来的是良好的灵活性和易维护性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值