Перейти к основному содержимому

Небольшие интерфейсы

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

Интерфейсы PHP естественно подходят под это правило: класс объявляет ровно те интерфейсы, которые реализует, — и ничего больше, — а когда какому-то коду действительно нужно несколько способностей, небольшие интерфейсы объединяются через extends. Пока каждый интерфейс остаётся крошечным, любой список implements остаётся честным.


«Толстый» интерфейс

Интерфейс Worker с методами work() и eat() выглядит безобидно — пока на работу не устроится робот. Робот прекрасно работает, но ему придётся реализовать и eat(), ответив... хоть чем-нибудь. Такие бессмысленные ответы — верный признак «толстого» интерфейса.

Робот, вынужденный есть

Робот реализует eat() только потому, что этого требует интерфейс. Обеденный перерыв выводит ответ, которого вообще не должно существовать, — класс был вынужден соврать.

Prompt
Напишите PHP-скрипт, показывающий нарушение принципа разделения интерфейсов: «толстый» интерфейс Worker с методами work и eat, класс Human, который умеет и то и другое, и класс Robot, вынужденный реализовать eat с бессмысленным ответом. Прогоните рабочую смену и обеденный перерыв по обоим, чтобы показать вынужденную ложь робота.
Вывод: PHP-скрипт

Разделите интерфейс

Разделите «толстый» интерфейс на Worker и Eater. Человек реализует оба, робот — только Worker. Рабочая смена принимает работников, обеденный перерыв — тех, кто ест, и робота просто никогда не приглашают на обед, а ни один метод не врёт.

Каждый класс реализует только свою правду

Два небольших интерфейса вместо одного «толстого». У робота больше вообще нет метода eat() — указание типа Eater автоматически не пускает его на обеденный перерыв.

Prompt
Исправьте «толстый» интерфейс в PHP, разделив его: интерфейс Worker с методом work и интерфейс Eater с методом eat. Human реализует оба, Robot — только Worker. Прогоните рабочую смену по обоим, а обеденный перерыв — только по тем, кто ест.
Вывод: PHP-скрипт
Each class implements only its truth

Небольшие части объединяются

Небольшие интерфейсы — это не ограничение: они объединяются. Когда какой-то функции действительно нужны обе способности, соедините их в один интерфейс: WorkingEater extends Worker, Eater.

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

Объединяйте, когда нужны обе способности

WorkingEater собран из двух небольших интерфейсов с помощью extends. Человек объявляет этот один интерфейс и тем самым считается и Worker, и Eater: полному рабочему дню нужны обе способности, поэтому подходит только человек.

Prompt
Покажите композицию интерфейсов в PHP: объедините небольшие интерфейсы Worker и Eater в интерфейс WorkingEater с помощью extends и напишите функцию fullDay, которая требует его, — тогда подходит только Human, реализующий WorkingEater. Выведите полный день человека.
Вывод: PHP-скрипт