关键环节 | MVC | MVP | 差异解析 |
---|---|---|---|
事件传递起点 | View → Controller | View → Presenter | ✅ 相同 |
Model 操作方 | Controller 直接修改 Model | Presenter 直接修改 Model | ✅ 相同 |
View 更新触发方 | Model 自动通知 View (观察者模式) | Presenter 主动调用 View 接口 | 最核心区别 |
View-Model 关系 | View 可直接监听 Model | View 和 Model 完全隔离 | 关键架构差异 |
数据获取方式 | View 直接从 Model 读取数据 | View 只能通过 Presenter 获取数据 | 重要区别 |
# Model (不变)
class UserModel:
def get_user(self) -> dict:
return {"name": "Alice", "age": 30}
# View 接口 (强制隔离)
class IUserView: # MVP 核心:接口抽象
def show_loading(self): pass
def display_user(self, user: dict): pass
def show_error(self, msg: str): pass
# 具体 View 实现
class UserView(IUserView):
def __init__(self, presenter):
self.presenter = presenter
self.btn = Button("加载用户", self.on_button_click) # UI 控件
# 点击事件:仅传递,不做逻辑处理
def on_button_click(self):
self.presenter.load_user_data() # → 转交 Presenter
# 以下实现接口方法(被动响应)
def show_loading(self):
print("加载中...")
def display_user(self, user):
print(f"姓名: {user['name']}, 年龄: {user['age']}")
def show_error(self, msg):
print(f"错误: {msg}")
# Presenter (业务逻辑中心)
class UserPresenter:
def __init__(self, view: IUserView):
self.view = view
self.model = UserModel()
def load_user_data(self):
try:
self.view.show_loading() # 主动控制UI状态
user = self.model.get_user() # 操作Model
self.view.display_user(user) # 主动更新View
except Exception as e:
self.view.show_error(str(e)) # 主动处理错误
View 的完全被动性
IUserView
)Presenter 的绝对控制权
# Presenter 控制完整流程
def load_user_data(self):
self.view.show_loading() # 1. 控制UI状态
data = self.model.get_data() # 2. 获取数据
self.view.render(data) # 3. 更新UI
self.log_analytics() # 4. 其他逻辑
测试优势的实际体现
# 测试 Presenter(无需真实 View 和 Model)
class MockView(IUserView):
def display_user(self, user):
assert user["name"] == "Alice" # 验证逻辑正确性
def test_presenter():
view = MockView()
presenter = UserPresenter(view)
presenter.load_user_data() # 纯逻辑测试
场景 | MVC 实现 | MVP 实现 | MVP 优势 |
---|---|---|---|
更换数据源 | 需修改 View(监听新Model) | 仅修改 Presenter | ✅ 更少改动 |
同一逻辑支持多平台UI | View 包含平台相关代码 | 实现新 View 接口即可 | ✅ 复用核心 |
单元测试业务逻辑 | 需启动完整 MVC 环境 | 直接测试 Presenter + Mock View | ✅ 效率提升 |
典型案例:Android 从 MVC 转向 MVP/MVVM
旧问题:Activity 既当 View 又当 Controller → 代码臃肿难测试
解决方案:用 Presenter 剥离业务逻辑
模式 | 核心指令流 | 组件关系 | 适用场景 |
---|---|---|---|
MVC | View → Controller → Model → View | View 知道 Model | 简单应用/框架内置 |
MVP | View → Presenter → Model → Presenter → View | 双向隔离 | 高测试要求/复杂交互 |
简单记忆: