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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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