SOLID — это акроним пяти ключевых принципов объектно-ориентированного программирования и проектирования, которые помогают создавать поддерживаемый, расширяемый и понятный код. Давайте разберем каждый принцип с примерами на Swift.
Определение: Класс должен иметь только одну причину для изменения, то есть только одну ответственность.
Пример нарушения:
class DataHandler {
func fetchData() { /* ... */ }
func parseData() { /* ... */ }
func saveToDatabase() { /* ... */ }
func displayInUI() { /* ... */ } // Нарушение! UI логика в классе работы с данными
}
Исправленный вариант:
class DataFetcher {
func fetch() { /* ... */ }
}
class DataParser {
func parse() { /* ... */ }
}
class DatabaseManager {
func save() { /* ... */ }
}
class DataDisplayer {
func display() { /* ... */ }
}
Определение: Программные сущности должны быть открыты для расширения, но закрыты для модификации.
Пример нарушения:
class PaymentProcessor {
func processPayment(type: String) {
if type == "credit" {
// обработка кредита
} else if type == "paypal" {
// обработка PayPal
} // При добавлении нового типа нужно модифицировать класс
}
}
Исправленный вариант:
protocol PaymentMethod {
func process()
}
class CreditCardPayment: PaymentMethod {
func process() { /* ... */ }
}
class PayPalPayment: PaymentMethod {
func process() { /* ... */ }
}
class PaymentProcessor {
func process(payment: PaymentMethod) {
payment.process()
}
}
Определение: Объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности программы.
Пример нарушения:
class Bird {
func fly() { /* ... */ }
}
class Penguin: Bird {
override func fly() {
fatalError("Пингвины не летают!") // Нарушение LSP
}
}
Исправленный вариант:
protocol Bird {
func move()
}
class FlyingBird: Bird {
func move() { /* летает */ }
}
class NonFlyingBird: Bird {
func move() { /* плавает или ходит */ }
}
Определение: Клиенты не должны зависеть от методов, которые они не используют.
Пример нарушения:
protocol Worker {
func work()
func eat()
func sleep()
}
class Human: Worker {
// Должен реализовать все методы
}
class Robot: Worker {
func eat() { /* не нужно роботу */ }
func sleep() { /* не нужно роботу */ }
}
Исправленный вариант:
protocol Workable {
func work()
}
protocol Eatable {
func eat()
}
protocol Sleepable {
func sleep()
}
class Human: Workable, Eatable, Sleepable {
// Реализует только нужные протоколы
}
class Robot: Workable {
// Только работа
}
Определение: Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.
Пример нарушения:
class LightBulb {
func turnOn() { /* ... */ }
}
class Switch {
private let bulb = LightBulb() // Прямая зависимость
func operate() {
bulb.turnOn()
}
}
Исправленный вариант:
protocol Switchable {
func turnOn()
}
class LightBulb: Switchable {
func turnOn() { /* ... */ }
}
class Switch {
private let device: Switchable
init(device: Switchable) { // Зависимость через абстракцию
self.device = device
}
func operate() {
device.turnOn()
}
}
SOLID — это не строгие правила, а руководства для создания качественного кода. В iOS-разработке эти принципы особенно важны из-за динамической природы платформы и необходимости поддерживать приложения долгие годы. Применяя SOLID, вы создаете архитектуру, которая выдерживает изменения требований и рост команды. Однако важно соблюдать баланс — не стоит применять принципы фанатично там, где это избыточно.