Что означает буква I в принципах SOLID?

Ответ

I означает Interface Segregation Principle (ISP)Принцип разделения интерфейсов.

Формулировка: Клиенты не должны зависеть от методов интерфейса, которые они не используют. Вместо одного «толстого» интерфейса лучше создать несколько небольших, специфичных.

Проблема — нарушение ISP:

// «Толстый» интерфейс заставляет класс Robot реализовывать ненужный метод.
protocol Worker {
    func work()
    func eat()
}

class Human: Worker {
    func work() { print("Человек работает") }
    func eat() { print("Человек ест") }
}

class Robot: Worker {
    func work() { print("Робот работает") }
    func eat() { /* Пустая или выброшенная ошибка — нарушение принципа! */ }
}

Решение — следование ISP:

// Интерфейсы разделены по ответственности.
protocol Workable {
    func work()
}

protocol Eatable {
    func eat()
}

class Human: Workable, Eatable { ... } // Реализует оба
class Robot: Workable { ... }          // Реализует только нужное

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

  • Уменьшает связность (coupling) между классами.
  • Избавляет классы от пустых или заглушечных реализаций.
  • Делает систему более гибкой и устойчивой к изменениям.

Ответ 18+ 🔞

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

Так и в коде. Этот принцип, I, он как раз про то, чтобы не пихать всем подряд один жирный интерфейс на всех. Принцип разделения интерфейсов, блядь. Суть проще пареной репы: клиентам (классам) не должны навязывать методы, которые им нахуй не сдались.

Смотри, какой пиздец бывает, если его нарушить:

// Вот этот уродец — типичный «толстый» интерфейс. Работник, блядь, универсальный.
protocol Worker {
    func work()
    func eat() // А вот это уже пиздец!
}

class Human: Worker {
    func work() { print("Человек работает") }
    func eat() { print("Человек ест в столовой") } // Ну, ок, человеку есть надо.
}

class Robot: Worker {
    func work() { print("Робот работает 24/7") }
    func eat() { /* И что мне тут писать, блядь?! */ } // Пустая заглушка! Нарушение, ёбаный насос!
}

Вообще пиздец, да? Робота заставляют eat() реализовывать! Он что, батарейки будет жрать через этот метод? Бред сивой кобылы!

А теперь смотри, как надо, по-красоте:

// Бам! И интерфейсы разделили. Каждый отвечает за своё.
protocol Workable {
    func work()
}

protocol Eatable {
    func eat()
}

class Human: Workable, Eatable {
    func work() { print("Человек работает") }
    func eat() { print("Человек ест") } // Всё чётко, всё по делу.
}

class Robot: Workable {
    func work() { print("Робот работает") }
    // И ни один ебучий `eat()` мне не навязывают! Красота!
}

И что мы, сука, выигрываем?

  • Связность меньше, блядь. Классы не привязаны к тому, что им не нужно. Роботу похуй на интерфейс Eatable.
  • Никаких пустышек. Не надо вот этого позорного func eat() { } или выброса ошибки. Код чистый.
  • Гибче система. Захотел добавить Rechargeable для роботов — хуяк, и добавил, не трогая людей. И наоборот.

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