MVP 是《MVC 模式》到《MVVM 模式》之间的过渡形态,Android 早期开发几乎人手一个。它解决的是 MVC 里"Controller 和 View 耦合紧"的问题。这篇把它讲清楚:Presenter 和 Controller 到底差在哪、为什么它更解耦、又为什么后来被 MVVM 取代。
一、解决什么问题:MVC 的 Controller 和 View 耦合
MVC 里 Controller 直接操作 View:
// MVC:Controller 直接往 Model 塞数据、指定视图
model.addAttribute("order", order); // 直接操作 View 的数据
return "order/detail"; // 直接指定视图前端一变(视图名改、参数改),Controller 就要跟着改——Controller 和 View 绑在一起。
MVP 的思路:View 完全被动,Presenter 通过"接口"操作 View,让 View 和业务彻底隔离。
二、三部分 + Presenter 替代 Controller
| 部分 | 职责 | 特点 |
|---|---|---|
| Model | 数据 + 业务逻辑 | 和 MVC 一样 |
| View | 纯展示 + 上报用户操作 | 完全被动,不含逻辑 |
| Presenter | 处理所有逻辑,通过接口操作 View | 替代 Controller,是核心 |
关键在 Presenter:它持有 View 的接口引用(不是具体 View),逻辑处理完后,通过接口去更新界面。View 只知道"Presenter 让我显示啥",不知道数据从哪来。
三、数据流
MVP 的数据流,Presenter 是绝对核心:
View 上报事件 → Presenter 处理 → 调 Model → Presenter 拿到结果 → 通过接口更新 ViewView 和 Model 完全不认识,中间全靠 Presenter 中转。
四、Android 落地(经典写法)
MVP 在 Android 是经典模式,Activity 就是 View:
// ① View 接口:定义界面能做什么
public interface LoginView {
void showLoading();
void showSuccess();
void showError(String msg);
}
// ② Presenter:处理逻辑,通过 View 接口操作界面
public class LoginPresenter {
private LoginView view;
private UserModel model = new UserModel();
public LoginPresenter(LoginView view) { this.view = view; }
public void login(String name, String pwd) {
view.showLoading(); // 通过接口操作 View
if (model.check(name, pwd)) { // 调 Model 校验
view.showSuccess();
} else {
view.showError("账号或密码错误");
}
}
}
// ③ Activity 实现 View 接口:只负责"显示什么"
public class LoginActivity extends Activity implements LoginView {
private LoginPresenter presenter;
@Override
protected void onCreate(Bundle b) {
presenter = new LoginPresenter(this);
findViewById(R.id.login).setOnClickListener(v ->
presenter.login(getName(), getPwd()) // 只上报事件,不处理逻辑
);
}
public void showLoading() { /* 显示加载中 */ }
public void showSuccess() { /* 跳转主页 */ }
public void showError(String msg) { /* 弹错误 */ }
}关键:LoginActivity 里没有业务逻辑——它只实现 LoginView 接口"显示什么",逻辑全在 LoginPresenter。想测登录逻辑,直接 mock 一个 LoginView 就能单测 Presenter,不用起 Activity。
五、MVP vs MVC
| 维度 | MVC | MVP |
|---|---|---|
| View 是否知道 Model | 知道(会读 Model 数据渲染) | 不知道(只跟 Presenter 打交道) |
| View 角色 | 主动读数据展示 | 完全被动,等 Presenter 通过接口投喂 |
| 中间角色 | Controller(协调) | Presenter(主导,核心逻辑) |
| View 和 Model | 有联系 | 彻底隔离(经 Presenter) |
| 可测试性 | 一般 | 好(Presenter 可脱离 View 单测) |
注:MVC 里 View 读 Model 有两种形式——经典 MVC 是 View 订阅 Model(观察者模式),Web MVC(Spring)是 Controller 把数据塞进 Model 容器、View 读容器渲染。但不管是哪种,MVC 的 View 都"知道 Model 的存在";而 MVP 的 View 完全不知道 Model,这是两者的本质区别。
"View 订阅 Model"是什么?会不会很像 MVVM?
确实很像——因为 MVVM 就是从这个机制演化来的,区别只在"手动"还是"自动":
// 经典 MVC:View 用观察者模式订阅 Model,收到通知后"手动"更新
class OrderModel {
private List<OrderView> views = new ArrayList<>();
private String status;
void attach(OrderView v) { views.add(v); } // ① 订阅:View 把自己注册进来
void setStatus(String s) {
status = s;
for (OrderView v : views) v.onModelChanged(); // ③ 通知:状态一变,挨个通知
}
String getStatus() { return status; }
}
class OrderView {
private OrderModel model; // View 持有 Model 引用
private Label label;
OrderView(OrderModel model) {
this.model = model;
model.attach(this); // ② 订阅动作:构造时把自己注册进 Model
}
void onModelChanged() { // ④ 收到通知:手动拉数据 + 更新界面
label.setText(model.getStatus());
}
}
// 使用:View 一创建,就自动订阅了 Model
OrderModel model = new OrderModel();
OrderView view = new OrderView(model); // ← 订阅发生在这里(构造器里 attach)
model.setStatus("已支付"); // ← 状态一变,view.onModelChanged() 被自动调用// MVVM:框架自动绑定,View 不用写 onModelChanged 这套
// <TextView android:text="@{viewModel.status}" /> // 声明绑定
// status 一变,框架自动刷新,View 零更新代码区别一句话:两者都是"数据变 → View 更新",但经典 MVC 要 View 手动写 onModelChanged(),MVVM 把它做成了框架的自动绑定。所以 MVVM 就是经典 MVC 观察者机制的"框架化版本"(详见《MVVM 模式》)。
顺带看出经典 MVC 的一个痛点:上面 View 直接持有 Model、直接
model.getStatus(),View 和 Model 耦合很严重——Model 的字段一改名,View 就得跟着改。而 MVP 让 View 连 Model 的存在都不知道(只依赖 View 接口),正是为了解开这个耦合。
一句话:MVP 把 MVC 里"View 和 Controller 的耦合"解开了,用 Presenter + View 接口彻底隔离。
六、MVP 的问题(为什么被 MVVM 取代)
MVP 解耦了,但代价也不小:
- 样板代码爆炸:每个界面都要写一个 View 接口 + 一个 Presenter,接口方法一堆(
showLoading/showSuccess/showError...),界面一多就写吐 - Presenter 要手动更新 View:逻辑里到处
view.showXxx(),更新点一多还是繁琐
这正是《MVVM 模式》要解决的——注意,"手动更新 View"这个痛点 MVC 也有(Controller 手动塞数据),MVP 只是把它换成了 Presenter 手动;MVVM 用"双向绑定"彻底干掉"手动更新"这个体力活。
小结
- MVP 用 Presenter 替代 Controller,解决 MVC 里 View 和 Controller 耦合的问题
- View 完全被动(只实现接口),Presenter 是核心(逻辑 + 通过接口操作 View)
- View 和 Model 彻底隔离,Presenter 可脱离 View 单测
- 遗留问题:样板代码爆炸、Presenter 手动更新 View → 引出 MVVM
下一步看《MVVM 模式》——它用双向绑定,让 View 自动同步,不再需要 Presenter 一行行手动更新。
