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

Маленькие интерфейсы

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

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


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

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

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

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

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

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

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

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

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

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

Маленькие части складываются

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

Именно к этому и стоит стремиться: описывайте маленькие интерфейсы и позвольте тому, кому нужно больше, склеить их с помощью extends.

Составляйте, когда нужны обе способности

WorkingEater построен из двух маленьких интерфейсов. Полному рабочему дню нужны обе способности, поэтому подходит только человек — и сказано это один раз, в системе типов.

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