项目架构
Solid

SOLID 原则

一、SOLID 原则总览

SOLID 原则是面向对象设计(OOP)的五大核心设计原则,由 Robert C. Martin(“Uncle Bob”)提出,用于指导我们编写高内聚、低耦合、可维护、可扩展的代码。

SOLID 分别代表:

  • S:Single Responsibility Principle(单一职责原则)
  • O:Open/Closed Principle(开闭原则)
  • L:Liskov Substitution Principle(里氏替换原则)
  • I:Interface Segregation Principle(接口隔离原则)
  • D:Dependency Inversion Principle(依赖倒置原则)

二、Single Responsibility Principle(单一职责原则)

问题:

什么是单一职责原则?在 iOS 项目中如何体现?

答案:

定义:

一个类应该只有一个引起它变化的原因。也就是说,每个类、结构体或模块都应该只负责一件事。

在 iOS 中的体现:

  • ViewController 不应同时负责网络请求、业务逻辑、UI 更新。
  • 可通过 MVVM / MVP 等架构将视图逻辑与业务逻辑分离。
  • 例如:
class UserViewModel {
    func fetchUserInfo() { ... } // 网络请求
}

class UserViewController: UIViewController {
    let viewModel = UserViewModel()
    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.fetchUserInfo()
    }
}

好处:

  • 降低代码复杂度,提升可维护性。
  • 单元测试更容易。

三、Open/Closed Principle(开闭原则)

问题:

什么是开闭原则?Swift 中如何实现?

答案:

定义:

软件实体(类、模块、函数等)应该对扩展开放,对修改关闭

意思是当需求变化时,应通过“扩展”而不是“修改”原有代码实现新功能。

在 Swift 中常见实现方式:

  • 利用 protocol + extension 实现扩展行为。
  • 使用 多态(继承或协议实现)

示例:

protocol Payment {
    func pay(amount: Double)
}

class ApplePay: Payment {
    func pay(amount: Double) { print("ApplePay: \(amount)") }
}

class PayPal: Payment {
    func pay(amount: Double) { print("PayPal: \(amount)") }
}

class PaymentProcessor {
    func process(payment: Payment, amount: Double) {
        payment.pay(amount: amount)
    }
}

新增支付方式时,无需修改 PaymentProcessor,只需新增类实现 Payment。


四、Liskov Substitution Principle(里氏替换原则)

问题:

什么是里氏替换原则?违反它会带来什么问题?

答案:

定义:

子类对象必须能够替换父类对象,而不影响程序正确性。

换句话说,子类应当遵守父类的契约,不应削弱父类功能。

示例(违反 LSP):

class Bird {
    func fly() { print("Flying") }
}

class Penguin: Bird {
    override func fly() { fatalError("Penguins can't fly") } // ❌
}

Penguin 无法替代 Bird 使用,会破坏里氏替换原则。

正确做法:

将会飞与不会飞的行为抽象为协议:

protocol Flyable { func fly() }

class Sparrow: Flyable { func fly() { print("Flying") } }
class Penguin { }

五、Interface Segregation Principle(接口隔离原则)

问题:

什么是接口隔离原则?在 Swift 中如何体现?

答案:

定义:

客户端不应被迫依赖它不使用的接口

一个大的接口应被拆分成多个小接口,让实现类只需关心自己需要的部分。

示例:

protocol Worker {
    func work()
    func eat()
}

class Human: Worker {
    func work() { print("Coding") }
    func eat() { print("Eating") }
}

class Robot: Worker {
    func work() { print("Working") }
    func eat() { fatalError("Robots don’t eat!") } // ❌
}

改进后:

protocol Workable { func work() }
protocol Eatable { func eat() }

class Human: Workable, Eatable { ... }
class Robot: Workable { ... }

这样各类只实现所需的接口。


六、Dependency Inversion Principle(依赖倒置原则)

问题:

什么是依赖倒置原则?在 Swift 开发中如何实践?

答案:

定义:

高层模块不应依赖低层模块,两者都应依赖于抽象(接口)

换句话说,要依赖抽象而不是具体实现

示例:

protocol NetworkService {
    func fetchData() -> String
}

class APIService: NetworkService {
    func fetchData() -> String { return "Data from API" }
}

class ViewModel {
    private let service: NetworkService
    init(service: NetworkService) {
        self.service = service
    }
    func loadData() {
        print(service.fetchData())
    }
}

ViewModel 只依赖 NetworkService 协议,而不依赖具体实现 APIService,便于测试与扩展。


七、综合应用与面试思路

在 iOS 面试中,面试官常考察:

  • 对 SOLID 原则的理解是否能落实到架构(MVC/MVVM/VIPER 等)。
  • 是否能通过 协议、泛型、依赖注入(DI) 实现可扩展设计。
  • 是否能识别违反原则的反例(如 Massive ViewController)。

答题建议:

  • 先简明说出定义。
  • 再结合 Swift 举例。
  • 最后说明实际项目中的好处。

确认总结:

SOLID 原则是 iOS 架构设计的思想根基。掌握并灵活运用它们,能让代码更健壮、更易测试、更易扩展。