之前有看过MVP的介绍,也没有实际的用过,今天学弟问我有没有用过MVP,就一起来研究研究。
提到MVP,就不得不说说MVC模式,MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。
- Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
- View(视图) - 视图代表模型包含的数据的可视化。
- Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
MVC 分层有助于管理复杂的应用程序,因为我们可以在一个时间内专门关注一个方面。例如,我们可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。
由结构图我们可以看到,在MVC模式中,虽然Controller控制着数据流向以及视图,但是View和Model之间也存在直接交互,在Android的开发中,我们通常都会把逻辑代码卸载Activity中,这样就会是的Activity逐渐变得臃肿不堪,为了解决这样的问题,就引入了新的模式,即MVP。
在MVP中,Prensenter(表示器)取代了MVC中的Controller,同时Activity的职责发生了变化,由原来的C变成了 V,不再管控制层的问题,只管如何去显示。控制层的角色就由我们的新人 Presenter来担当,这种架构就解决了Activity过度耦合控制层和视图层的问题。还有一点就是Presenter与View之间的交互是通过接口的且V和M不可以直接进行交互。
由于身边环境的限制,我将以JAVA中的GUI开发演示MVP的开发方式,毕竟我们主要是阐述MVP的思想。我们一一个登录作为例子,将我们的包及代码结构搭建起来。
包结构如下:
我们先来看一下Model层中的接口和实现类:
package com.jianggujin.mvp.model;
public interface LoginModel
{
void login(String name, String pass, OnLoginFinishedListener listener);
public interface OnLoginFinishedListener
{
void onNameError();
void onPassError();
void onSuccess();
}
}
package com.jianggujin.mvp.model.impl;
import com.jianggujin.mvp.model.LoginModel;
public class LoginModelImpl implements LoginModel
{
@Override
public void login(String name, String pass, OnLoginFinishedListener listener)
{
if (isEmpty(name))
{
listener.onNameError();
return;
}
if (isEmpty(pass))
{
listener.onPassError();
return;
}
listener.onSuccess();
}
private boolean isEmpty(String msg)
{
return msg == null || msg.length() == 0;
}
}
在用户登录的模型中,我们使用login方法来模拟用户名密码的校验。
接下来,我们来看View层中的接口和实现类。
package com.jianggujin.mvp.view;
public interface LoginView
{
void setNameError();
void setPassError();
void setSuccess();
}
package com.jianggujin.mvp.view.impl;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import com.jianggujin.mvp.presenter.LoginPresenter;
import com.jianggujin.mvp.presenter.impl.LoginPresenterImpl;
import com.jianggujin.mvp.view.LoginView;
@SuppressWarnings("serial")
public class LoginViewImpl extends JFrame implements LoginView
{
private LoginPresenter presenter;
private JTextField userNameText;
private JPasswordField passwordText;
private JButton loginButton;
public LoginViewImpl()
{
super("登录");
presenter = new LoginPresenterImpl(this);
userNameText = new JTextField(20);
passwordText = new JPasswordField(20);
loginButton = new JButton("登录");
loginButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
presenter.validateCredentials(userNameText.getText(), new String(passwordText.getPassword()));
}
});
Box root = Box.createVerticalBox();
root.add(userNameText);
root.add(passwordText);
root.add(loginButton);
add(root);
this.pack();
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
@Override
public void setNameError()
{
JOptionPane.showMessageDialog(this, "用户名错误", "错误", JOptionPane.ERROR_MESSAGE);
}
@Override
public void setPassError()
{
JOptionPane.showMessageDialog(this, "密码错误", "错误", JOptionPane.ERROR_MESSAGE);
}
@Override
public void setSuccess()
{
JOptionPane.showMessageDialog(this, "登录成功", "提示", JOptionPane.INFORMATION_MESSAGE);
}
}
登录的视图仅负责页面的展示,当存在与用户交互的时候,将交由LoginPresenter处理。
最后,我们来看Presenter层中的接口和实现类。
package com.jianggujin.mvp.presenter;
public interface LoginPresenter
{
void validateCredentials(String name, String pass);
}
package com.jianggujin.mvp.presenter.impl;
import com.jianggujin.mvp.model.LoginModel;
import com.jianggujin.mvp.model.LoginModel.OnLoginFinishedListener;
import com.jianggujin.mvp.model.impl.LoginModelImpl;
import com.jianggujin.mvp.presenter.LoginPresenter;
import com.jianggujin.mvp.view.LoginView;
public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener
{
private LoginView loginView;
private LoginModel loginModel;
public LoginPresenterImpl(LoginView loginView)
{
this.loginView = loginView;
loginModel = new LoginModelImpl();
}
@Override
public void validateCredentials(String name, String pass)
{
loginModel.login(name, pass, this);
}
@Override
public void onNameError()
{
loginView.setNameError();
}
@Override
public void onPassError()
{
loginView.setPassError();
}
@Override
public void onSuccess()
{
loginView.setSuccess();
}
}
Presenter扮演着View和Model的中间层的角色。获取model层的数据之后构建view层;也可以收到view层UI上的反馈命令后分发处理逻辑,交给model层做业务操作。它也可以决定View层的各种操作。