Ответ
Разделение объектов в первую очередь связано с принципом разделения интерфейсов (ISP) из SOLID. Его цель — избегать создания "толстых" интерфейсов, которые вынуждают клиентов (классы) реализовывать методы, которые им не нужны.
Почему это важно:
- Уменьшает связность — классы зависят только от того, что им действительно нужно.
- Повышает поддерживаемость — изменения в одном интерфейсе затрагивают меньшее количество кода.
- Предотвращает загрязнение кода — исчезает необходимость в пустых реализациях методов (например,
throw new NotImplementedException).
Пример на PHP:
// Проблема: "Толстый" интерфейс
interface WorkerInterface {
public function code();
public function test();
public function deploy();
public function cook(); // Не нужно программисту!
}
class Programmer implements WorkerInterface {
public function code() { /* ... */ }
public function test() { /* ... */ }
public function deploy() { /* ... */ }
public function cook() { // Вынужденная пустая реализация
throw new RuntimeException('I cannot cook!');
}
}
// Решение: Разделенные интерфейсы
interface CoderInterface {
public function code();
}
interface TesterInterface {
public function test();
}
interface DeploymentInterface {
public function deploy();
}
interface ChefInterface {
public function cook();
}
// Теперь класс реализует только нужные ему интерфейсы
class Programmer implements CoderInterface, TesterInterface {
public function code() { /* ... */ }
public function test() { /* ... */ }
}
class DevOpsEngineer implements CoderInterface, DeploymentInterface {
public function code() { /* ... */ }
public function deploy() { /* ... */ }
}
На практике это часто применяется при проектировании сервисов или модулей, чтобы они были сфокусированы на одной ответственности.
Ответ 18+ 🔞
А, ну это же классика, ёпта! Сейчас объясню на пальцах, без всей этой заумной лабуды. Представь себе, что ты заказываешь в столовой комплексный обед. Тебе приносят тарелку, а там суп, котлета, пюре, компот и... блядь, селёдка под шубой. Ты её не заказывал, она тебе нахуй не нужна, но она есть, и ты за неё заплатил. Вот это и есть «толстый» интерфейс — тебе впарили кучу всякого дерьма, от которого только тошнит.
А зачем это вообще нужно?
- Чтобы не тащить за собой овердохуища ненужного хлама. Зачем программисту уметь готовить? Ему бы код не сломать. Если заставлять его реализовывать метод
cook(), он либо оставит его пустым, либо, что ещё хуже, кинет исключение, как в примере. И потом какой-нибудь ебанько вызовет этот метод и получит ошибку в самом неожиданном месте. Доверия к такому коду — ноль ебать. - Чтобы не было сюрпризов. Меняешь что-то в одном методе интерфейса — и понеслась: надо бегать и проверять, не сломалось ли что в двадцати классах, которые этот интерфейс используют, даже если им этот метод нахуй не сдался. Терпения на такое — ноль ебать.
- Чтобы код был как швейцарский нож, а не как манда с ушами. Каждый инструмент — для своего дела. Хочешь резать — бери лезвие. Хочешь открыть бутылку — бери открывалку. А не пытайся открыть пиво тем, что должно было быть отвёрткой, но стало каким-то пиздопроебибным универсальным монстром.
Смотри, как это выглядит в коде:
Сначала — пиздец как неправильно. Как будто на дворе 2002-й год и все пишут, не думая.
// Это пиздец, чувак. Интерфейс-универсал. Настоящая хитрая жопа.
interface WorkerInterface {
public function code();
public function test();
public function deploy();
public function cook(); // Программисту это зачем? Чтобы лапшу быстрого приготовления варить?
}
class Programmer implements WorkerInterface {
public function code() { /* ... */ } // Ок
public function test() { /* ... */ } // Ладно, пусть будет
public function deploy() { /* ... */ } // Ну, иногда и самому надо
public function cook() { // А это что за хуйня?!
// Вынужден писать эту хуйню, иначе код не скомпилируется
throw new RuntimeException('Я не умею готовить, я программист, ёпта!');
}
}
Видишь? Класс Programmer — полупидор. Он и программист, и повар, но повар-то него кривой, потому что метод просто кидает ошибку. Удивление пиздец.
А теперь — как надо. Красиво, элегантно, по SOLID-у.
// Разделили всё по полочкам. Каждый интерфейс — одна чёткая способность.
interface CoderInterface {
public function code();
}
interface TesterInterface {
public function test();
}
interface DeploymentInterface {
public function deploy();
}
interface ChefInterface {
public function cook();
}
// Программист. Чистый, красивый. Делает то, что умеет.
class Programmer implements CoderInterface, TesterInterface {
public function code() { /* Пишет код */ }
public function test() { /* Тестирует свой же код */ }
}
// Дефопс инженер. Кодит и деплоит. Никакой лишней хуйни.
class DevOpsEngineer implements CoderInterface, DeploymentInterface {
public function code() { /* Пишет скрипты */ }
public function deploy() { /* Запускает в прод */ }
}
// А вот шеф-повар. Он только готовит. И ему похуй на ваш код.
class Chef implements ChefInterface {
public function cook() { /* Готовит селёдку под шубой */ }
}
Вот и вся магия, ебушки-воробушки. Каждый занимается своим делом, не тянет за собой лишний груз, и если ты завтра захочешь изменить что-то в процессе готовки, тебе надо будет лезть только в класс Chef. Все программисты останутся в полной безопасности и не получат случайно ложкой в глаз.
На практике это значит: не делай из своего сервиса или класса хуй в пальто, который пытается делать всё. Разделяй логику на мелкие, сфокусированные куски. Так жить проще, и код не превращается в помойку, где всё связано со всем.