Ответ
SOLID — это пять ключевых принципов объектно-ориентированного проектирования, направленных на создание гибкого, поддерживаемого и расширяемого кода.
1. Single Responsibility (Принцип единственной ответственности) Класс должен иметь одну и только одну причину для изменения.
// ПЛОХО: Класс занимается и логикой, и сохранением
class User {
func validate() { ... }
func saveToDatabase() { ... }
}
// ХОРОШО: Разделение ответственности
class UserValidator {
func validate(_ user: User) -> Bool { ... }
}
class UserRepository {
func save(_ user: User) { ... }
}
2. Open-Closed (Принцип открытости/закрытости) Классы должны быть открыты для расширения, но закрыты для модификации.
protocol PaymentMethod {
func processPayment(amount: Double)
}
class CreditCardPayment: PaymentMethod {
func processPayment(amount: Double) { ... }
}
class PayPalPayment: PaymentMethod {
func processPayment(amount: Double) { ... }
}
class PaymentProcessor {
func process(payment: PaymentMethod, amount: Double) {
payment.processPayment(amount: amount)
}
}
3. Liskov Substitution (Принцип подстановки Барбары Лисков) Объекты должны быть заменяемыми экземплярами своих базовых классов без изменения корректности программы.
// Нарушение принципа:
class Bird {
func fly() { ... }
}
class Penguin: Bird { // Пингвин не может летать!
override func fly() {
fatalError("Penguins can't fly")
}
}
// Решение: Разделить интерфейсы
protocol Bird {
func eat()
}
protocol FlyingBird: Bird {
func fly()
}
4. Interface Segregation (Принцип разделения интерфейса) Много специализированных интерфейсов лучше, чем один универсальный.
// ПЛОХО: Один громоздкий протокол
protocol Worker {
func work()
func eat()
func sleep()
}
// ХОРОШО: Разделенные протоколы
protocol Workable {
func work()
}
protocol Eatable {
func eat()
}
class Robot: Workable { // Роботу не нужно есть
func work() { ... }
}
5. Dependency Inversion (Принцип инверсии зависимостей) Зависимости должны строиться на абстракциях, а не на конкретных реализациях.
// ПЛОХО: Зависимость от конкретного класса
class DataService {
private let database = MySQLDatabase() // Жесткая привязка
}
// ХОРОШО: Зависимость от абстракции
protocol Database {
func save(data: Any)
}
class DataService {
private let database: Database
init(database: Database) { // Внедрение зависимости
self.database = database
}
}
Практическое применение:
- Использую протоколы для абстракции зависимостей
- Разделяю большие классы на мелкие с одной ответственностью
- Применяю Dependency Injection для тестируемости
- Следую принципам осознанно, но без фанатизма — иногда прагматизм важнее строгого следования догмам