Android设计模式之浅谈MVP
一.概述
MVP(Model-View-Presenter) 是总所周知MVC模式的一个演变,他们的主要目的都是划分模块职责,降低模块耦合,易测试,提高代码复用,这里主要针对Android平台来简单分析MVP.
1.层级责任
Model: 负责数据的检索,持久化等操作
View: 负责UI的绘制和用户的交互
Presenter: 作为Model和View的中间协调部分,负责两者之间的业务逻辑处理
2.与MVC模式的区别
MVP模式与MVC模式从层级数据流向上来说一个主要的区别应该就是:MVC模式允许View层和Model层直接通讯.从图1和图2可以看到MVP和MVC的区别.
图1MVC模式中Model可以直接update data 到View层。所以当某个View的功能很复杂的时候,View和Model的耦合度可能会很高(并且在android的开发中Activity通常会充当controller&view的角色,结果Activity就很臃肿).而MVP模式就没有这个问题,View会抽象出来一系列操作UI的接口(Model层也可以),Presenter拿到的都是其他两个层级的接口来做业务逻辑的处理.这样不仅可以使View和Model之间的耦合度降低,还可以更易得进行单元测试.
图1:MVC模式
图2:MVP模式
3.MVP的优缺点
优点:降低耦合,层级职责更明显,易于单元测试
缺点:造成类数量爆炸,代码复杂度和学习成本高,在某些场景下presenter的复用会产生接口冗余
二. MVP简单的实例
使用MVP 写一个简单的登陆功能,主页就两个按钮:Login 和 Clear
1.项目结构
2.Model层
包含有一个实体UserBean用来承载数据和UserBiz来对登陆数据判断
-
public class UserBean {
-
private String username;
-
private String password;
-
public String getUsername() {
-
return username;
-
}
-
public void setUsername(String username) {
-
this.username = username;
-
}
-
public String getPassword() {
-
return password;
-
}
-
public void setPassword(String password) {
-
this.password = password;
-
}
-
}
UserBiz通过抽象出一个接口
-
public interface UserBiz {
-
public void login(UserBean login);
-
}
UserBizImpl实例化接口,并且通过登陆监听将结果回调给Presenter
-
public class UsrBizImpl implements UserBiz{
-
private OnLoginListener listener;
-
public UsrBizImpl(OnLoginListener listener){
-
this.listener = listener;
-
}
-
@Override
-
public void login(UserBean login) {
-
boolean status = false;
-
String username,password;
-
username = login.getUsername();
-
password = login.getPassword();
-
if (username != null && "asdf".equals(username))
-
if (password != null && "123".equals(password))
-
status = true;
-
listener.loginStatus(status);
-
}
-
}
3.View层
把View层针对控件操作抽象出来一些列的接口
-
public interface LoginView {
-
public String getUsername();
-
public String getPassword();
-
public void clearUsername();
-
public void clearPassword();
-
public void showMsg(String msg);
-
}
在Activity里面实现该接口的控件操作,并且初始化Presenter,这是可以看到Activity里面没有逻辑处理,只是对UI的控件进行数据或者行为的操作,所有的动作都是有Presenter的接口来实现,这样在项目里面会极大得精简Activity的体积.
-
public class LoginActivity extends Activity implements LoginView{
-
private EditText username, password;
-
private Button login, clear;
-
private LoginPresenter loginPresenter;
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.activity_login);
-
init();
-
}
-
private void init(){
-
loginPresenter = new LoginPresenterImpl(this);
-
username = (EditText) findViewById(R.id.username);
-
password = (EditText) findViewById(R.id.pass);
-
login = (Button) findViewById(R.id.login);
-
clear = (Button) findViewById(R.id.clear);
-
login.setOnClickListener(new View.OnClickListener() {
-
@Override
-
public void onClick(View view) {
-
loginPresenter.login();
-
}
-
});
-
clear.setOnClickListener(new View.OnClickListener() {
-
@Override
-
public void onClick(View view) {
-
loginPresenter.clear();
-
}
-
});
-
}
-
@Override
-
public String getUsername() {
-
return username.getText().toString();
-
}
-
@Override
-
public String getPassword() {
-
return password.getText().toString();
-
}
-
@Override
-
public void clearUsername() {
-
username.setText("");
-
}
-
@Override
-
public void clearPassword() {
-
password.setText("");
-
}
-
@Override
-
public void showMsg(String msg) {
-
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
-
}
-
}
4.Presenter层
在Presenter层里面,Presenter掌握着View和Model的所有接口,Presenter就可以根据不同的业务逻辑通过MV两层的接口来实现特定的功能,让M和V独立出来.
-
public class LoginPresenterImpl implements LoginPresenter, OnLoginListener{
-
private UserBiz userBiz;
-
private LoginView loginView;
-
public LoginPresenterImpl(LoginView loginView){
-
this.loginView = loginView;
-
userBiz = new UsrBizImpl(this);
-
}
-
@Override
-
public void login() {
-
UserBean login = new UserBean();
-
login.setUsername(loginView.getUsername());
-
login.setPassword(loginView.getPassword());
-
userBiz.login(login);
-
}
-
@Override
-
public void clear() {
-
loginView.clearPassword();
-
loginView.clearUsername();
-
}
-
@Override
-
public void loginStatus(boolean status) {
-
String msg;
-
if (status)
-
msg = "login succeed";
-
else
-
msg = "login failed";
-
loginView.showMsg(msg);
-
}
-
}