Swift中SOLID原则简介
\n每个iOS开发者迟早都会遇到“意大利面条式代码”的问题:类变得臃肿,一处修改导致整个应用崩溃,测试变成噩梦。解决这些问题的基础在于面向对象设计——SOLID原则。这五条由Robert Martin提出的规则,帮助你在Swift中创建灵活、可维护且可扩展的代码。在本文中,我们将从理论到实际iOS/macOS示例逐一剖析每个原则。
\n无论你使用UIKit、SwiftUI还是AppKit,SOLID都是一个通用基础。让我们深入细节。
\n\n1. 单一职责原则(SRP)
\n理论
\n一个类应该只有一个引起变化的原因。换句话说,每个模块只负责一个功能。如果你的ViewController管理UI、处理网络请求并解析JSON——它就违反了SRP。
\nSwift实践
\n考虑一个典型示例——加载和显示用户数据。
\n// ❌ 糟糕:违反SRP\nclass UserViewController: UIViewController {\n func loadUser() {\n // 网络请求\n let url = URL(string: "https://api.example.com/user")!\n URLSession.shared.dataTask(with: url) { data, _, _ in\n let user = try? JSONDecoder().decode(User.self, from: data!)\n DispatchQueue.main.async {\n self.updateUI(with: user)\n }\n }.resume()\n }\n \n func updateUI(with user: User?) {\n // 更新UI\n }\n}\n// ✅ 良好:分离职责\nclass UserService {\n func fetchUser(completion: @escaping (User?) -> Void) {\n let url = URL(string: "https://api.example.com/user")!\n URLSession.shared.dataTask(with: url) { data, _, _ in\n let user = try? JSONDecoder().decode(User.self, from: data!)\n completion(user)\n }.resume()\n }\n}\n\nclass UserViewController: UIViewController {\n let userService = UserService()\n \n func loadUser() {\n userService.fetchUser { [weak self] user in\n DispatchQueue.main.async {\n self?.updateUI(with: user)\n }\n }\n }\n \n private func updateUI(with user: User?) {\n // 更新UI\n }\n}\n结论:现在UserService只负责网络,而UserViewController只负责UI。网络逻辑的修改不会影响控制器。
2. 开闭原则(OCP)
\n理论
\n类应该对扩展开放,对修改关闭。与其修改现有代码,我们通过继承或协议添加新功能。在Swift中,协议和扩展是实现这一点的理想工具。
\nSwift实践
\n假设我们正在编写一个电商应用的折扣计算模块。
\n// ❌ 糟糕:添加新折扣时需要修改类\nclass DiscountCalculator {\n func calculate(price: Double, type: String) -> Double {\n if type == "seasonal" {\n return price * 0.9\n } else if type == "loyalty" {\n return price * 0.85\n }\n return price\n }\n}\n// ✅ 良好:使用协议进行扩展\nprotocol DiscountStrategy {\n func applyDiscount(to price: Double) -> Double\n}\n\nstruct SeasonalDiscount: DiscountStrategy {\n func applyDiscount(to price: Double) -> Double {\n price * 0.9\n }\n}\n\nstruct LoyaltyDiscount: DiscountStrategy {\n func applyDiscount(to price: Double) -> Double {\n price * 0.85\n }\n}\n\nclass DiscountCalculator {\n func calculate(price: Double, strategy: DiscountStrategy) -> Double {\n strategy.