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

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

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

В Python интерфейс записывается как класс-протокол, и маленькие протоколы здесь вполне естественны: сам язык работает на крошечных протоколах — любой объект с методом __next__() работает со встроенной функцией next(), и большая часть стандартной библиотеки опирается на столь же маленькие обещания.


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

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

Робот, которого заставляют есть

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

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

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

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

Каждый класс реализует только то, что для него верно

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

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

Маленькие части объединяются

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

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

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

WorkingEater построен из двух маленьких протоколов. Для полного рабочего дня нужны обе способности, поэтому подходит только человек — и это сказано один раз, в системе типов.

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