MVP(Model-View-Presenter)是MVC(Model-View-Controller)架构的一种演进模式,主要用于改善MVC在UI交互和测试方面的局限性。它在桌面应用(如Java Swing、.NET WinForms)和Android开发中广泛应用,后来也被一些Web框架(如GWT)采用。
1. MVP 核心组件#
组件 | 职责 |
---|---|
Model | 负责数据逻辑(如数据库、网络请求、业务规则),与MVC中的Model类似。 |
View | 负责UI展示(如Activity、Fragment、Web页面),但不处理业务逻辑。 |
Presenter | 作为View和Model的中间人,处理用户交互,更新Model并通知View刷新。 |
2. MVP 工作原理#
- 用户操作View(如点击按钮)。
- View将事件转发给Presenter(不直接处理逻辑)。
- Presenter调用Model获取或更新数据。
- Model返回结果给Presenter。
- Presenter更新View(如显示数据、错误提示)。
关键特点:
- View是被动的:仅负责渲染UI,不直接与Model交互。
- Presenter是主动的:控制流程,决定何时更新View和Model。
- Model独立:与View无直接依赖,便于测试和复用。
3. MVP 的优势#
(1) 更清晰的职责分离#
- View只负责显示,Presenter处理逻辑,避免MVC中Controller和View的模糊边界。
- 适合复杂UI交互(如表单验证、多步骤流程)。
(2) 更高的可测试性#
- Presenter不依赖Android API或DOM,可直接用JUnit测试。
- View可通过Mock对象测试,无需真实UI环境。
(3) 降低耦合#
- View通过接口(如
IView
)与Presenter通信,便于替换UI框架(如从Android转向Flutter)。 - Model可独立修改,不影响View。
(4) 解决MVC的“胖Controller”问题#
- MVC的Controller可能混杂业务逻辑和UI逻辑,而MVP的Presenter更专注于流程控制。
4. MVP 的缺点#
(1) 代码量增加#
- 需要定义View接口(如
ILoginView
)和Presenter,对小项目可能显得冗余。
(2) Presenter可能变“胖”#
- 复杂页面可能导致Presenter逻辑膨胀,需进一步拆分(如按功能模块分多个Presenter)。
(3) 手动绑定较繁琐#
- 需要显式编写View和Presenter的绑定代码(现代框架如MVVM通过数据绑定自动化)。
5. MVP vs. MVC vs. MVVM#
特性 | MVC | MVP | MVVM |
---|---|---|---|
View职责 | 可能包含逻辑 | 完全被动 | 完全被动 |
数据绑定 | 无(或手动) | 手动(Presenter更新View) | 自动(双向绑定) |
测试难度 | 较高(依赖UI) | 低(Presenter可独立测试) | 低(ViewModel可测试) |
典型框架 | Spring MVC、Ruby on Rails | Android、GWT | Vue.js、WPF、Jetpack Compose |
6. MVP 代码示例(Android)#
(1) 定义View接口#
public interface ILoginView {
void showLoading();
void hideLoading();
void onLoginSuccess(String message);
void onLoginError(String error);
}
java(2) Presenter 实现#
public class LoginPresenter {
private ILoginView view;
private UserModel model;
public LoginPresenter(ILoginView view) {
this.view = view;
this.model = new UserModel();
}
public void login(String username, String password) {
view.showLoading();
model.login(username, password, new Callback() {
@Override
public void onSuccess() {
view.hideLoading();
view.onLoginSuccess("登录成功!");
}
@Override
public void onFailure(String error) {
view.hideLoading();
view.onLoginError(error);
}
});
}
}
java(3) View(Activity)实现#
public class LoginActivity extends AppCompatActivity implements ILoginView {
private LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
presenter = new LoginPresenter(this);
Button btnLogin = findViewById(R.id.btn_login);
btnLogin.setOnClickListener(v -> {
String username = editUsername.getText().toString();
String password = editPassword.getText().toString();
presenter.login(username, password);
});
}
@Override
public void showLoading() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
progressBar.setVisibility(View.GONE);
}
// 其他接口方法...
}
java7. 适用场景#
- Android开发:Activity/Fragment作为View,Presenter处理业务逻辑。
- 桌面应用:如Java Swing、.NET WinForms。
- 需要高测试性的项目:单元测试覆盖Presenter逻辑。
总结#
MVP通过被动View和主动Presenter解决了MVC的部分问题,尤其适合UI逻辑复杂的场景。但随着现代框架(如MVVM、Flux)的兴起,MVP在部分领域已被替代,但在Android传统开发中仍有一席之地。