引言:为什么 SOLID 对 Swift 开发者很重要
每位 iOS 开发者迟早都会遇到"意大利面条式代码"的问题:控制器膨胀到数千行,修改一个实体破坏另外三个,测试变成噩梦。SOLID 原则是面向对象设计的五个基本规则,有助于在 Swift 中创建灵活、可维护且可测试的代码。
在本文中,我们将通过 iOS 开发中的具体示例逐一解析每个 SOLID 原则。您将学习如何在实际项目中应用这些原则,避免典型错误。本文对初级开发者和希望系统化知识的有经验开发者都很有帮助。
1. Single Responsibility Principle (SRP) — 单一职责原则
核心思想:每个类应该只有一个修改原因。换句话说,一个类应该只负责一个任务。
问题:"万能"的 ViewController
典型错误是将所有逻辑放入 UIViewController。看一个糟糕的例子:
class UserProfileViewController: UIViewController { @IBOutlet weak var nameLabel: UILabel! func loadUser() { // 1. 网络逻辑 let url = URL(string: "https://api.example.com/user")! URLSession.shared.dataTask(with: url) { data, _, _ in // 2. JSON 解析 let user = try! JSONDecoder().decode(User.self, from: data!) // 3. 保存到 Core Data self.saveToCoreData(user) // 4. 更新 UI DispatchQueue.main.async { self.nameLabel.text = user.name } }.resume() } private func saveToCoreData(_ user: User) { /* ... */ }}解决方案:分离职责
将代码拆分为独立的组件:
// 1. 网络服务class UserNetworkService { func fetchUser(completion: @escaping (Result<User, Error>) -> Void) { let url = URL(string: "https://api.example.com/user")! URLSession.shared.dataTask(with: url) { data, _, error in if let data = data { do { let user = try JSONDecoder().decode(User.self, from: data) completion(.success(user)) } catch { completion(.failure(error)) } } else if let error = error { completion(.failure(error)) } }.resume() }}
// 2. 数据存储管理器class UserStorageManager { func save(_ user: User) { // 保存到 Core Data / Realm 的逻辑 }}
// 3. ViewModel (或 Presenter)class UserViewModel { private let networkService = UserNetworkService() private let storageManager = UserStorageManager() var onUserUpdated: ((User) -> Void)? func loadUser() { networkService.fetchUser { [weak self] result in switch result { case .success(let user): self?.storageManager.save(user) self?.onUserUpdated?(user) case .failure(let error): print(error.localizedDescription) } } }}
// 4. ViewController 现在只管理 UIclass UserProfileViewController: UIViewController { @IBOutlet weak var nameLabel: UILabel! private let viewModel = UserViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.onUserUpdated = { [weak self] user in DispatchQueue.main.async { self?.nameLabel.text = user.name } } viewModel.loadUser() }}结果:每个类只有一个修改原因。测试和维护这样的代码会显著