Что такое принцип открытости/закрытости (Open-Closed Principle)

Ответ

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

Пример нарушения OCP:

class Shape(val type: String) {
    fun area(): Double {
        return when(type) {
            "circle" -> /* расчёт для круга */
            "square" -> /* расчёт для квадрата */
            else -> 0.0
        }
    }
}

Правильный подход:

interface Shape {
    fun area(): Double
}

class Circle : Shape { /* реализация */ }
class Square : Shape { /* реализация */ }

Преимущества:

  • Уменьшает риск сломать существующий код
  • Упрощает добавление новой функциональности
  • Делает код более поддерживаемым

Ответ 18+ 🔞

Э, слушай, вот есть такая штука — принцип открытости/закрытости. Звучит как какая-то хуйня из философии, но на деле всё просто, ёпта. Суть в том, что твой класс должен быть открыт для расширения, но закрыт для модификации. То есть, если тебе нужно добавить новую фичу, ты не лезешь в старый код с паяльником и отвёрткой, а расширяешь его через наследование или композицию. Исходники остаются нетронутыми, как девственница в монастыре.

Смотри, как это нарушают все, кому не лень. Вот типичный пример говнокода:

class Shape(val type: String) {
    fun area(): Double {
        return when(type) {
            "circle" -> /* расчёт для круга */
            "square" -> /* расчёт для квадрата */
            else -> 0.0
        }
    }
}

Ну и что тут не так, спросишь? А то, что каждый раз, когда тебе понадобится добавить, скажем, треугольник, ты будешь лезть прямо в этот метод area() и пихать туда новый case. Это пиздопроебибна идея! Представь, у тебя этот класс используют в двадцати местах, а ты туда лазишь — волнение ебать, терпения ноль ебать. Один неверный чих — и всё, накрылось медным тазом, система легла.

А теперь правильный подход, где мы не идём на поводу у своей хитрой жопы:

interface Shape {
    fun area(): Double
}

class Circle : Shape { /* реализация */ }
class Square : Shape { /* реализация */ }

Видишь разницу? Теперь, чтобы добавить тот самый треугольник, тебе не нужно ковыряться в старом классе. Просто создаёшь новый класс Triangle, который реализует интерфейс Shape, и пишешь там свою логику. Старый код даже не узнает, что его расширили — доверия ебать ноль, но зато и риска ноль.

Какие плюсы? Да овердохуища!

  • Риск сломать работающий код стремится к нулю. Не трогаешь — не ломаешь. Гениально и просто.
  • Добавлять новую функциональность — одно удовольствие. Не нужно рыскать по всему проекту в поисках всех when или if, куда нужно впендюрить новое условие.
  • Код становится поддерживаемым. Через полгода ты посмотришь на это и не будешь материться, пытаясь понять, какого хуя тут расчёт площади для семиугольника засунут между кругом и квадратом.

Короче, запомни: пиши так, чтобы завтра можно было легко добавить новую фичу, не превращая сегодняшний код в манду с ушами.