文章目录
20220109(原)
- View: 是显示数据(model)并且将用户指令(events)传送到presenter以便作用于那些数据的一个接口。View通常含有Presenter的引用。在Android开发中通常将Activity或者Fragment作为View层。
- Model: 对于Model层也是数据层。它区别于MVC架构中的Model,在这里不仅仅只是数据模型。在MVP架构中Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。
- Presenter:对于Presenter层他是连接View层与Model层的桥梁并对业务逻辑进行处理。在MVP架构中Model与View无法直接进行交互。所以在Presenter层它会从Model层获得所需要的数据,进行一些适当的处理后交由View层进行显示。这样通过Presenter将View与Model进行隔离,使得View和Model之间不存在耦合,同时也将业务逻辑从View中抽离。
20250321 MVP模式全解析
背景概述
MVP(Model-View-Presenter)模式是一种衍生于经典MVC架构的界面设计模式,旨在优化代码组织结构并提高可测试性。该模式通过明确划分职责边界,使得界面逻辑与业务逻辑彻底分离,为复杂应用开发提供了强大支撑。
MVP核心架构
Model层(Model层负责数据管理与业务逻辑)
- 封装核心业务规则和数据状态
- 独立于UI层,不感知界面变化
- 提供数据访问接口与数据操作方法
- 通常包含实体类、服务类和数据源
View层(View层专注于界面展示)
- 被动接收指令,展示数据
- 将用户交互事件委托给Presenter处理
- 不包含业务逻辑,仅负责UI呈现
- 通常由Activity、Fragment或自定义View实现
Presenter层(Presenter层作为核心协调者)
- 连接Model与View的桥梁
- 处理View层传递的用户事件
- 从Model获取数据并格式化后交给View显示
- 包含应用逻辑但不直接操作UI元素
MVP与MVC对比(MVC:Model、View、Controller)
结构差异
- MVC模式中,Controller作为中央协调者,同时View可直接访问Model
MVC: View ←→ Controller ←→ Model
↑______________________|
- MVP模式中,Presenter完全隔离View和Model:
MVP: View ←→ Presenter ←→ Model
交互方式
- MVC:View可直接观察Model变化
- MVP:View与Model完全解耦,所有交互通过Presenter中转
测试性(MVP显著提高了测试覆盖率)
具体原因如下:
- Presenter不依赖具体UI实现
- 可通过模拟View进行单元测试
- 业务逻辑集中在Presenter,便于编写测试用例
MVP实现示例
定义契约接口
public interface TaskContract {
interface View {
void showTasks(List<Task> tasks);
void showTaskDetails(Task task);
void showLoadingError();
void showLoading(boolean active);
}
interface Presenter {
void loadTasks();
void openTaskDetails(Task task);
void addNewTask();
void start();
}
}
Model实现
public class TaskRepository {
private TaskDataSource localDataSource;
private TaskDataSource remoteDataSource;
public void getTasks(LoadTasksCallback callback) {
// 实现数据获取逻辑
// ...
}
public void saveTask(Task task) {
// 实现数据保存逻辑
// ...
}
}
Presenter实现
public class TaskPresenter implements TaskContract.Presenter {
private final TaskRepository repository;
private final TaskContract.View view;
public TaskPresenter(TaskRepository repository, TaskContract.View view) {
this.repository = repository;
this.view = view;
}
@Override
public void loadTasks() {
view.showLoading(true);
repository.getTasks(new LoadTasksCallback() {
@Override
public void onTasksLoaded(List<Task> tasks) {
view.showLoading(false);
view.showTasks(tasks);
}
@Override
public void onDataNotAvailable() {
view.showLoading(false);
view.showLoadingError();
}
});
}
// 其他方法实现...
}
View实现
public class TaskActivity extends AppCompatActivity implements TaskContract.View {
private TaskContract.Presenter presenter;
private TaskAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_task);
// 初始化Presenter
presenter = new TaskPresenter(
TaskRepository.getInstance(),
this
);
// 初始化视图组件
RecyclerView recyclerView = findViewById(R.id.task_list);
adapter = new TaskAdapter();
recyclerView.setAdapter(adapter);
// 启动Presenter
presenter.start();
}
@Override
public void showTasks(List<Task> tasks) {
adapter.setTasks(tasks);
adapter.notifyDataSetChanged();
}
// 其他方法实现...
}
MVP优势分析
结构优势
- 关注点分离:UI逻辑与业务逻辑明确区分
- 模块独立性:各模块可独立开发和测试
- 代码复用:Presenter可跨多个View复用
开发效率
- 团队协作更高效,前端与后端开发可并行
- 接口定义明确,减少沟通成本
- 模块化程度高,便于功能扩展
维护性
- 代码职责清晰,易于理解
- 修改范围可控,降低连锁反应风险
- 问题定位准确,便于调试
MVP变种
Passive View
- View极度被动,几乎不包含任何逻辑
- Presenter控制一切UI交互和状态变化
- 最高程度的View-Model解耦
Supervising Controller
- View可以直接绑定简单数据
- Presenter仅处理复杂UI逻辑
- 在简单场景中可提高效率
MVP实践建议
接口设计
- 为每个功能模块定义明确的契约接口
- 根据单一职责原则拆分大型接口
- 避免"万能"接口导致耦合
生命周期管理
- 处理View生命周期变化(尤其在Android平台)
- 防止内存泄漏(弱引用、解绑操作)
- 优雅处理Presenter销毁逻辑
适用场景
- 复杂业务逻辑的企业级应用
- 需要高测试覆盖率的项目
- 多人协作的中大型项目
常见问题与解决方案
Presenter臃肿
随着业务复杂度增加,Presenter可能变得臃肿。解决方案:
- 引入UseCase/Interactor分担业务逻辑
- 按功能垂直拆分Presenter
- 结合依赖注入简化Presenter
额外代码量
MVP模式需要编写大量接口和委托代码。缓解方法:
- 使用代码生成工具
- 建立基类封装通用逻辑
- 只在复杂模块应用MVP,简单UI可使用其他模式
结语
MVP模式通过明确的职责划分和模块化设计,为应用开发提供了清晰的架构指导。在实际应用中,需要根据项目特点灵活调整其实现细节,避免教条化使用。随着响应式编程和MVVM模式兴起,MVP也在不断演进,但其核心理念仍然是现代软件设计的重要基石。