MVP(Model-View-Presenter) 是一种常见的 软件架构模式,用于分离应用程序的 UI 逻辑与业务逻辑,它类似于 MVC(Model-View-Controller),但与 MVC 相比,MVP 更加强调了 Presenter 作为中介者的角色,进一步解耦了视图与数据的处理逻辑。
在 iOS 开发 中使用 MVP 架构模式 时,主要有三个核心组成部分:
- Model(模型层):负责应用程序的数据和业务逻辑,通常会包含网络请求、数据库操作、模型数据等内容。
- View(视图层):负责展示界面和与用户的交互。它不包含任何业务逻辑,而是通过调用 Presenter 来更新视图。
- Presenter(展示层):处理用户交互逻辑,它是连接 View 和 Model 的桥梁。Presenter 通过请求 Model获取数据,并通过 View 更新 UI。
MVP 与 MVC 的区别
- MVC 中,Controller 既负责用户交互,也负责更新视图。它充当了视图和模型之间的中介,但通常会导致控制器变得过于臃肿。
- MVP 中,Presenter 专注于业务逻辑和用户交互,View 只负责展示和用户交互,而 Presenter 执行大部分的业务逻辑。
MVP 架构的三个主要角色
1. Model(模型层)
- 负责持久化数据、业务逻辑、与网络接口交互等。
- 通常是数据模型和服务层的集合。
- 例如:网络请求、数据存储等。
struct User {
var name: String
var age: Int
}
class UserService {
func fetchUserData(completion: @escaping (User) -> Void) {
// 假设这是从服务器获取数据
let user = User(name: "John", age: 25)
completion(user)
}
}
2. View(视图层)
- 负责所有与 UI 相关的操作,如显示数据、接收用户输入。
- View 只负责展示,不处理任何业务逻辑。
- View 通过协议向 Presenter 通知用户的交互(例如按钮点击、文本输入等)。
protocol UserView: AnyObject {
func displayUserData(user: User)
}
class UserViewController: UIViewController, UserView {
var presenter: UserPresenter!
override func viewDidLoad() {
super.viewDidLoad()
presenter = UserPresenter(view: self)
presenter.loadUserData()
}
func displayUserData(user: User) {
// 更新 UI,显示用户数据
print("User name: \(user.name), age: \(user.age)")
}
}
3. Presenter(展示层)
- 负责从 Model 获取数据,并更新 View。
- Presenter 持有对 View 的引用,并可以调用 View 上的方法来更新 UI。
- 它充当了中介的角色,负责决定如何处理数据并与 View 进行交互。
protocol UserPresenterProtocol {
func loadUserData()
}
class UserPresenter: UserPresenterProtocol {
weak var view: UserView?
var userService: UserService
init(view: UserView) {
self.view = view
self.userService = UserService()
}
func loadUserData() {
userService.fetchUserData { [weak self] user in
self?.view?.displayUserData(user: user)
}
}
}
MVP 架构的流程
- View 初始化时,创建 Presenter 并调用 Presenter 方法来加载数据。
- Presenter 通过调用 Model 层来获取数据(如网络请求、数据库访问等)。
- 数据获取后,Presenter 更新 View,让 View 展示新的数据。
主要优点
- 解耦性高:业务逻辑(Presenter)与 UI 逻辑(View)分开,易于维护和扩展。
- 单元测试友好:由于 Presenter 完全不依赖于 UI,可以方便地对其进行单元测试,而不需要依赖于界面。
- 可重用性:由于 Presenter 和 View 解耦,你可以轻松地为不同平台(iPhone, iPad)或者不同 UI 层次(例如:Modal vs. Normal View)重用 Presenter 层。
主要缺点
- Presenter 增加了复杂度:尽管 Presenter 提供了更多的解耦,但会使得架构相对更加复杂。需要更多的类来管理界面逻辑。
- 需要更多的协议与代码结构:每个 View 都需要一个对应的协议,增加了额外的抽象层级和代码复杂度。
适用场景
- 较为复杂的应用:如果你的应用包含多个业务逻辑层,并且需要与后端进行复杂的交互,使用 MVP 可以帮助保持代码的整洁。
- 单元测试要求高的应用:由于 Presenter 与 View 解耦,可以很方便地为 Presenter 写单元测试。
完整的示例
以下是一个完整的 MVP 架构示例,它展示了如何在 iOS 中实现这种架构。
// Model
struct User {
var name: String
var age: Int
}
class UserService {
func fetchUserData(completion: @escaping (User) -> Void) {
// 模拟网络请求
let user = User(name: "Alice", age: 30)
completion(user)
}
}
// View
protocol UserView: AnyObject {
func displayUserData(user: User)
}
class UserViewController: UIViewController, UserView {
var presenter: UserPresenterProtocol!
override func viewDidLoad() {
super.viewDidLoad()
presenter = UserPresenter(view: self)
presenter.loadUserData()
}
func displayUserData(user: User) {
print("User Name: \(user.name), Age: \(user.age)")
}
}
// Presenter
protocol UserPresenterProtocol {
func loadUserData()
}
class UserPresenter: UserPresenterProtocol {
weak var view: UserView?
var userService: UserService
init(view: UserView) {
self.view = view
self.userService = UserService()
}
func loadUserData() {
userService.fetchUserData { [weak self] user in
self?.view?.displayUserData(user: user)
}
}
}
小结
MVP(Model-View-Presenter) 架构模式通过 Presenter 充当中介者,将 View 和 Model 之间的逻辑分离开来。它为开发者提供了更清晰的代码结构,更高的可维护性和更易于测试的代码。然而,相比于 MVC,MVP 增加了额外的抽象和复杂度,适用于需要高度解耦和清晰的业务逻辑的应用场景。
发表回复