解析MVC和MVP设计模式的使用及优缺点

1.背景

  • MVC:是一种在20世纪80年代出现较早的设计模式。
  • MVP:由于MVC本身存在一定的弊端,后来出现了该设计模式

2.特点

2.1.MVC设计模式
  • 定义
    MVC是由Model(模型),View(视图),Controller(控制器)这三部分组成。
    Model:Model层主要是处理与业务相关的代码,与视图View是无关的。
    View:这里指的一般是XML代码,或者是自定义View绘制页面。简单来说指的就是页面可视化的部分。
    Controller:对Android来说,Controller通常指的就是activity、fragment包括有这些类控制的其他相关类。
  • 优缺点
    优点:代码之间的分工明确、一定程度上提高了开发效率。
    缺点:随着项目的复杂度提升,代码会变得很臃肿、View层和Model相互耦合,不易开发和维护。
2.2.MVP设计模式
  • 定义
    MVP是由Model(模型),View(视图),Presenter(提出者)这三部分组成。
    Model:主要提供数据的存储、获取功能。
    View:通常指的就是activity、fragment类包括一些展示View的类似于MVC的View差不多。
    Presenter:该类可以称之为View和Model类之间沟通的桥梁,主要就是通过实现接口的方式由Model层获取到数据返回给View层,从而View层和Model层之间的解偶合(写程序的要求是高内聚,低耦合)
  • 优缺点
    优点:低耦合、便于维护,成本低等
    缺点:需要创建的类过多,对于简单的页面使用MVP降低了可阅读性、需要关注activity或fragment的生命周期,例如在Presenter做网络请求成功回调的时候,要判断activity或fragment是否已被销毁,需要做的处理有点多,阅读性较差。

3.具体使用

3.1.MVC

  • 3.1.1.关系图如下:
Model
View
Controller
  • 3.1.2.MVC的例子没什么好说的,这里一笔带过,如果你还是不太清楚的话(点击这里
3.2.MVP
  • 3.2.1.关系图如下:
Model
Presenter
View
  • 3.2.2.接下来上代码(注意注释处的文字描述):

    • Activity类的代码
public class LoginActivity extends BaseActivity implements View.OnClickListener, LoginContract.View {
    ......
    
    private boolean showPassword;
    private LoginPresenter mPresenter;

    public static void start(Context context) {
        Intent intent = new Intent(context, LoginActivity.class);
        context.startActivity(intent);
    }

    @Override
    public int setContentLayout() {
        return R.layout.activity_login;
    }

    @Override
    public void initToolBar() {

    }

    @Override
    public void initPresenter() {
   		//注意:部分方法被封装到BaseActivity里面,最终是在onCreate()方法中有调用,
   		//也就是说Presenter类是在onCreate()里面new的,并且这里也可以不用判空。
        if (mPresenter == null) { 
            mPresenter = new LoginPresenter(this, this);
        }
    }

    @Override
    public void initData() {
        initListener();
    }

    @Override
    public void onDestroyActivity() {
    	//这个方法最终是在onDestory()方法中调用,所以在界面销毁时候要将Presenter对象置空,
    	//这里没有考虑网络请求可能出现延迟页面生命周期的情况。
        mPresenter = null;
    }

    private void initListener() {
       ......
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ib_delete_number:
                ......
                break;
            case R.id.ib_delete_password:
              	......
                break;
            case R.id.ib_hide_password:
                ......
                break;
            case R.id.btn_login:
                String number = mEtNumbers.getText().toString().trim();
                String password = mEtPasswords.getText().toString().trim();
                if (mPresenter != null) {
                	//下面这个方法是在接口类LoginContract.Presenter中申明的,后面会再做解释
                    mPresenter.manageNumberAndPassword(number, password);
                }
                break;
            case R.id.tv_register:
                RegisterActivity.start(this);
                break;
        }
    }

	//这个方法是在接口类LoginContract.View申明的,
	//在activity中实现LoginContract.View里面View接口的方法,在Presenter里面调用。
    @Override
    public void errorRemind(int title, int resId) {
       ......
    }
    
	//这个方法是在接口类LoginContract.View申明的,
	//在activity中实现LoginContract.View里面View接口的方法,在Presenter里面调用。
    @Override
    public void loginSuccess(int successRemind) {
        ToastUtil.showToast(this, successRemind);
        MainActivity.start(this);
        finish();
    }

	//这个方法是在接口类LoginContract.View申明的,
	//在activity中实现LoginContract.View里面View接口的方法,在Presenter里面调用。
    @Override
    public void loginError(String errorMsg) {
			......
    }


    class MyWatcher implements TextWatcher {
			......
    }
  • Presenter类的代码
public class LoginPresenter implements LoginContract.Presenter {

    private static final int mNumberLength = 11;
    private static final int mPasswordLength = 6;

    private Activity mActivity;
    private LoginContract.View mView;
    private final ILoginModel mModel;
	
	//将activity和presenter建立链接就是通过这个构造方法
    public LoginPresenter(Activity activity, LoginContract.View view) {
        this.mActivity = activity;
        this.mView = view;
        mModel = new LoginModel();//这里是网络请求的封装类,后面再做解释。
    }

	//这个方法实现的是LoginContract.Presenter这里的,上面activity那里有调用
    @Override
    public void manageNumberAndPassword(String number, String password) {
        if (mView == null) {
            return;
        }
        if (TextUtils.isEmpty(number) || TextUtils.isEmpty(password)) {
        	//这里mView指的是LoginContract.View的对象,errorRemind()方法是
        	//LoginContract.View接口类里的,在这里调用,在activity实现,下面同理。
            mView.errorRemind(R.string.login_dialog_error, R.string.login_dialog_error_content);
            return;
        }
        if (number.length() < mNumberLength || password.length() < mPasswordLength) {
            mView.errorRemind(R.string.login_dialog_remind, R.string.login_dialog_error_remind);
            return;
        }

        mModel.loginInfo(number, password, new ILoginModel.loginListener() {
            @Override
            public void responseLoginSuccess(LoginBean loginBean) {
                mView.loginSuccess(R.string.login_success);
            }

            @Override
            public void responseLoginFail(String errorMsg) {
                //请求失败
                mView.loginError(errorMsg);
            }
        });
    }
}
  • LoginContract接口类代码
//activity和Presenter是通过这个接口类关联起来的,这里要注意Presenter的构造方法。
public interface LoginContract {
	//在activity类实现View接口,Presenter类调用View接口
	//IBaseVeiw可以添加一写通用方法的封装
    interface View extends IBaseView {
        void errorRemind(int title, int reeId);

        void loginSuccess(int successRemind);

        void loginError(String errorMsg);
    }
	//在Presenter类里实现Presenter接口,在activity类调用Presenter接口
	//IBasePresenter可以添加一写通用方法的封装
    interface Presenter extends IBasePresenter {
        void manageNumberAndPassword(String number, String password);
    }
}
  • Model类代码
//通常Model类都是用来做网络请求的封装,这里用到的是RxJava2+Retrofit2做的封装
public class LoginModel implements  ILoginModel{

    @Override
    public void loginInfo(String phone, String pwd, final ILoginModel.loginListener listener) {

        new AppSubscribe.Builder()
                .setFlowable(BaseHttp.getBaseHttp().loginInfo(Constant.HTTP_KEY, phone, pwd))
                .subscribe(new AppResponse<LoginBean>() {
                    @Override
                    public void onNext(LoginBean loginBean) {
                        super.onNext(loginBean);
                        if (listener != null) {
                            listener.responseLoginSuccess(loginBean);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        if (listener != null) {
                            listener.responseLoginFail(e.getMessage());
                        }
                    }
                }).build();
    }
}
  • Model接口类代码
public interface ILoginModel {

    void loginInfo(String phone, String pwd, ILoginModel.loginListener listener);


    interface loginListener {

        void responseLoginSuccess(LoginBean loginBean);

        void responseLoginFail(String errorMsg);
    }
}

注:基本上MVP就是上面说的那个样子,如果没有看懂也没关系,根据下面第4步,下载代码会看可能会更容易理解一些。

4.参考

  • 如果你想了解(MVP+RxJava2+Retrofit2)组合的设计模式,请参考我的这个项目:Android_Demo持续完善

5.总结

5.最后

开通了个公众号,扫码关注一下,可以获得超过1个G的免费PDF书籍学习资料,并且可以及时收到我分享的内容哦!
在这里插入图片描述
期待你的关注!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值