开发过程中相信大部分人都使用过MVC设计模式,很多人会觉得此模式使用简单,而且在一定程度上使得代码结构清晰、易于维护。但是美中不足的是View视图和Model模型没有达到真正的解耦,如果代码量过大还是会造成代码的过于臃肿、可读性差,因此MVP设计模式就逐步走入了我们的视野中被广大开发者所熟知。
MVP是模型Model-视图View-主持人Presenter的缩写,Model负责建立数据结构和相应的业务逻辑操作;View负责界面数据的显示更新以及用户触发的各类事件响应;Presenter处理程序的各种逻辑分发,是模型与视图之间的桥梁。
在MVC设计模式中View视图是可以直接读取Model模型中的数据的,Model模型数据发生改变时会通知View视图的数据显示发生相应的改变。而在MVP设计模式中Model模型和View视图之间是没有直接联系的,它们是两个完全独立的模块,当Model模型发生数据改变时,会通过Presenter主持人通知View视图发生相应的UI改变。因此MVP设计模式相对于MVC设计模式实现了View视图和Model模型的完全分离,也就是说Model模型进行业务数据处理时和View视图数据显示没有任何关联。
代码结构图:
Model模型
1、Model接口
package com.wiggins.mvp.model;
import com.wiggins.mvp.listener.OnLoginListener;
/**
* @Description 登录操作接口
* @Author 一花一世界
* @Time 2017/1/17 16:17
*/
public interface LoginModel {
void login(String name, String password, OnLoginListener onLoginListener);
}
2、Model接口实现
package com.wiggins.mvp.model.imple;
import com.wiggins.mvp.listener.OnLoginListener;
import com.wiggins.mvp.model.LoginModel;
import com.wiggins.mvp.utils.NetworkUtils;
/**
* @Description 登录操作接口实现,这里主要是业务逻辑操作
* @Author 一花一世界
* @Time 2017/1/17 16:17
*/
public class LoginModelImple implements LoginModel {
@Override
public void login(String name, String password, final OnLoginListener onLoginListener) {
if (name.isEmpty()) {
onLoginListener.onUsernameEmpty();
} else if (password.isEmpty()) {
onLoginListener.onPasswordEmpty();
} else if (!name.equals("admin")) {
onLoginListener.onUsernameError();
} else if (!password.equals("123456")) {
onLoginListener.onPasswordError();
} else if (!NetworkUtils.isNetworkAvailable()) {
onLoginListener.onFailure();
} else {
onLoginListener.onSuccess();
}
}
}
View视图
1、View接口
package com.wiggins.mvp.view;
import android.content.Context;
/**
* @Description 登录View接口
* @Author 一花一世界
* @Time 2017/1/17 16:18
*/
public interface LoginView {
//上下文
Context getContext();
//登录成功后跳转到首页
void moveToIndex();
//Toast提示
void showToast(String msg);
//获取界面的用户名
String getName();
//获取界面的密码
String getPassword();
}
2、View接口实现
package com.wiggins.mvp.activity;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.wiggins.mvp.R;
import com.wiggins.mvp.presenter.LoginPresenter;
import com.wiggins.mvp.presenter.imple.LoginPresenterImple;
import com.wiggins.mvp.view.LoginView;
/**
* @Description mvp登录案例
* @Author 一花一世界
* @Time 2017/1/17 17:34
*/
public class LoginActivity extends Activity implements View.OnClickListener, LoginView {
private LoginActivity mActivity = null;
private EditText mEdtName;
private EditText mEdtPwd;
private Button mBtnLogin;
private LoginPresenter loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mActivity = this;
loginPresenter = new LoginPresenterImple(this);
initView();
setListener();
}
private void initView() {
mEdtName = (EditText) findViewById(R.id.edt_name);
mEdtPwd = (EditText) findViewById(R.id.edt_pwd);
mBtnLogin = (Button) findViewById(R.id.btn_login);
}
private void setListener() {
mBtnLogin.setOnClickListener(this);
}
@Override
public Context getContext() {
return mActivity;
}
@Override
public void moveToIndex() {
Intent intent = new Intent(mActivity, MainActivity.class);
startActivity(intent);
finish();
}
@Override
public void showToast(String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_LONG).show();
}
@Override
public String getName() {
return mEdtName.getText().toString().trim();
}
@Override
public String getPassword() {
return mEdtPwd.getText().toString().trim();
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_login:
loginPresenter.onLoginInfo();
break;
}
}
}
Presenter主持人
1、Presenter接口
package com.wiggins.mvp.presenter;
/**
* @Description 登录Presenter接口
* @Author 一花一世界
* @Time 2017/1/17 17:33
*/
public interface LoginPresenter {
void onLoginInfo();
}
2、Presenter接口实现
package com.wiggins.mvp.presenter.imple;
import com.wiggins.mvp.R;
import com.wiggins.mvp.listener.OnLoginListener;
import com.wiggins.mvp.model.LoginModel;
import com.wiggins.mvp.model.imple.LoginModelImple;
import com.wiggins.mvp.presenter.LoginPresenter;
import com.wiggins.mvp.view.LoginView;
/**
* @Description 负责完成登录界面View与Model之间的交互
* @Author 一花一世界
* @Time 2017/1/17 17:31
*/
public class LoginPresenterImple implements LoginPresenter {
private LoginModel loginModel;
private LoginView loginView;
public LoginPresenterImple(LoginView loginView) {
this.loginView = loginView;
loginModel = new LoginModelImple();
}
@Override
public void onLoginInfo() {
String name = loginView.getName();
String password = loginView.getPassword();
loginModel.login(name, password, new OnLoginListener() {
@Override
public void onUsernameEmpty() {
loginView.showToast(loginView.getContext().getResources().getString(R.string.name_not_empty));
}
@Override
public void onPasswordEmpty() {
loginView.showToast(loginView.getContext().getResources().getString(R.string.password_not_empty));
}
@Override
public void onUsernameError() {
loginView.showToast(loginView.getContext().getResources().getString(R.string.name_error));
}
@Override
public void onPasswordError() {
loginView.showToast(loginView.getContext().getResources().getString(R.string.password_error));
}
@Override
public void onSuccess() {
loginView.showToast(loginView.getContext().getResources().getString(R.string.login_successful));
loginView.moveToIndex();
}
@Override
public void onFailure() {
loginView.showToast(loginView.getContext().getResources().getString(R.string.login_failed));
}
});
}
}
回调接口
package com.wiggins.mvp.listener;
/**
* @Description 登录回调接口
* @Author 一花一世界
* @Time 2017/1/17 17:35
*/
public interface OnLoginListener {
//用户名为空
void onUsernameEmpty();
//密码为空
void onPasswordEmpty();
//用户名错误
void onUsernameError();
//密码错误
void onPasswordError();
//登录成功
void onSuccess();
//登录失败
void onFailure();
}
View与Model不直接进行交互,而是采用Presenter作为View与Model之间交互的桥梁。其中Presenter中同时持有View层以及Model层的Interface引用,而View层持有Presenter层的Interface引用。当View层的某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层进行数据请求,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。
MVP的优点:
- 易于维护:模块职责划分明确,层次清晰;
- 低耦合度:实现了
Model和View的分离; - 复用性高:一个
Presenter可以用于多个View; - 健壮稳定:代码容错性、可移植性强;
- 灵活性高:新增或修改需求无需更改原本的代码逻辑;
MVP的缺点:
- 对于不是很大的项目来说会提高代码的复杂及时间成本;
View视图的渲染放在了Presenter中,所以View视图和Presenter的交互会过于频繁;- 如果
Presenter过多地渲染了View视图,会使得它与特定视图的联系过于紧密,一旦视图需要更改,那么Presenter也需要更改了。
项目地址 ☞ 传送门
本文详细介绍了MVP设计模式的概念及其在实际项目中的应用。通过对比MVC模式,阐述了MVP模式如何实现View和Model的完全解耦,增强代码的可维护性和复用性。
4546

被折叠的 条评论
为什么被折叠?



