SOLID в Swift. Простое объяснение с примерами для начинающих

—

от автора

Принципы SOLID — это набор пяти основных принципов, которые помогают разработчикам создавать более понятный, гибкий и поддерживаемый код. Так же знание этих принципов довольно часто спрашивают на собеседованиях. Давайте рассмотрим каждый из этих принципов с примерами нарушения и соблюдения на языке Swift:

Принцип единственной ответственности (Single Responsibility Principle, SRP): Этот принцип гласит, что у каждого класса или структуры должна быть только одна задача. Например, если у вас есть класс для обработки данных из сети, его не следует использовать для отображения данных на экране.

Нарушение принципа SPR:

// NetworkManager только выполняет сетевые запросы class NetworkManager {     func fetchData(url: URL) {         // Запрос к API     }      func updateUI() {         // обновляет пользовательский интерфейс     } }

В этом примере класс NetworkManager нарушает принцип SPR, потому что он и получает данные из сети, и обновляет UI.

Соблюдение принципа SPR:

// NetworkManager только выполняет сетевые запросы class NetworkManager {     func fetchData(url: URL) {         // Запрос к API     } }  // ViewController управляет отображением данных class ViewController: UIViewController {     let networkManager = NetworkManager()      func updateUI() {         let url = URL(string: "https://api.example.com")!         networkManager.fetchData(url: url)         // Обновить интерфейс пользователя с данными     } }

Принцип открытости/закрытости (Open-Closed Principle, OCP): Классы и функции должны быть открыты для расширения, но закрыты для изменений. Это означает, что вы должны быть в состоянии добавить новую функциональность без изменения существующего кода. Это можно сделать с помощью протоколов и расширений в Swift.

Нарушение принципа OCP:

class Animal {     let name: String      init(name: String) {         self.name = name     }      func makeSound() {         if name == "Dog" {             print("Woof")         } else if name == "Cat" {             print("Meow")         }     } }

Здесь класс Animal не закрыт для модификации, потому что если мы захотим добавить новое животное, нам придется изменить метод makeSound.

Соблюдение принципа OCP:

protocol Animal {     func makeSound() }  class Dog: Animal {     func makeSound() {         print("Woof")     } }  class Cat: Animal {     func makeSound() {         print("Meow")     } }

Теперь каждый класс подписанный под протокол Animal может иметь свою собственную реализацию makeSound, и протокол Animal закрыт для модификаций.

Принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP): Это означает, что если у вас есть класс B, который является подклассом класса A, вы должны иметь возможность использовать B везде, где используется A, без изменения поведения программы.

Нарушение принципа LSP:

class Bird {     func fly() {         // Реализация полета     } }  class Penguin: Bird {     override func fly() {         fatalError("Penguins can't fly!")     } }  let myBird: Bird = Penguin() myBird.fly()  // Приведет к ошибке во время выполнения

В этом примере Penguin нарушает LSP, потому что он не может летать, в то время как класс Bird предполагает, что все птицы могут летать.

Соблюдение принципа LSP:

class Bird {     func move() {         print("The bird is flying")     } }  class Penguin: Bird {     override func move() {         print("The penguin is sliding")     } }   let myBird: Bird = Penguin() myBird.move()

Теперь каждый подкласс Bird может иметь свою собственную реализацию move, не нарушая поведение базового класса.

Принцип разделения интерфейса (Interface Segregation Principle, ISP): Это означает, что классы не должны зависеть от методов, которые они не используют. В Swift это можно сделать с помощью протоколов.

Нарушение принципа ISP:

protocol Worker {     func work()     func eat() }  class Robot: Worker {     func work() {         // работает     }      func eat() {         fatalError("Robots can't eat")     } }

Здесь Robot нарушает ISP, потому что он вынужден реализовать функцию eat, которую он не может использовать.

Соблюдение принципа ISP:

protocol Worker {     func work() }  protocol Eater {     func eat() }  class Robot: Worker {     func work() {         // работает     } }

Теперь Robot реализует только функции, которые он действительно может использовать.

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP): Это означает, что классы верхнего уровня не должны зависеть от классов нижнего уровня. Оба они должны зависеть от абстракций.

Нарушение принципа DIP:

class LightBulb {     func turnOn() {         // включает свет     } }  class Switch {     let bulb: LightBulb      init(bulb: LightBulb) {         self.bulb = bulb     }      func toggle() {         bulb.turnOn()     } }

Здесь класс Switch напрямую зависит от конкретного класса LightBulb, что нарушает DIP.

Соблюдение принципа DIP:

protocol Switchable {     func turnOn() }  class LightBulb: Switchable {     func turnOn() {         // включает свет     } }  class Switch {     let device: Switchable      init(device: Switchable) {         self.device = device     }      func toggle() {         device.turnOn()     } }

Теперь класс Switch зависит от абстракции, а не от конкретного класса, что соблюдает DIP.


ссылка на оригинал статьи https://habr.com/ru/articles/746410/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *