Приведи пример нарушения принципа SOLID в коде

«Приведи пример нарушения принципа SOLID в коде» — вопрос из категории ООП, который задают на 22% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нарушение Принципа единственной ответственности (Single Responsibility Principle - SRP): Класс ReportGenerator отвечает и за формирование данных отчета, и за их форматирование в HTML, и за отправку по email.

class ReportGenerator {
    func fetchData() -> Data { /* ... */ }
    func analyzeData(_ data: Data) -> AnalysisResult { /* ... */ }
    func createHTMLReport(from result: AnalysisResult) -> String { /* ... */ }
    func sendEmail(with html: String, to recipient: String) { /* ... */ }
}
// Нарушение: класс имеет как минимум три причины для изменения:
// 1. Изменение логики получения данных.
// 2. Изменение формата отчета (PDF, CSV).
// 3. Изменение способа доставки (сохранение в файл, push-уведомление).

Исправленная архитектура (соответствует SRP):

class DataFetcher { func fetch() -> Data { /* ... */ } }
class DataAnalyzer { func analyze(_ data: Data) -> AnalysisResult { /* ... */ } }
class HTMLReportBuilder { func build(from result: AnalysisResult) -> String { /* ... */ } }
class EmailSender { func send(content: String, to recipient: String) { /* ... */ } }
// Каждый класс имеет одну, четко определенную ответственность.

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

class AreaCalculator {
    func area(of shape: Any) -> Double {
        if let circle = shape as? Circle {
            return Double.pi * pow(circle.radius, 2)
        } else if let square = shape as? Square {
            return pow(square.side, 2)
        }
        // Добавление нового типа фигуры (Triangle) требует изменения этого метода.
        return 0
    }
}

Исправление с помощью протокола (соответствует OCP):

protocol Shape {
    var area: Double { get }
}

struct Circle: Shape {
    let radius: Double
    var area: Double { Double.pi * radius * radius }
}
struct Square: Shape {
    let side: Double
    var area: Double { side * side }
}
// Чтобы добавить Triangle, нужно создать новый тип, соответствующий протоколу Shape.
// Класс AreaCalculator изменять не требуется.
class AreaCalculator {
    func totalArea(of shapes: [Shape]) -> Double {
        return shapes.reduce(0) { $0 + $1.area }
    }
}