«I» означает принцип разделения интерфейсов и поощряет реализацию только того поведения, которое действительно требуется.

В программной архитектуре интерфейсы - это контракты, которые сами по себе не определяют поведения, но которого должны придерживаться другие модули. Они позволяют потребителю модуля знать, как разговаривать с модулем, не зная подробностей о нем.

Метафора об интерфейсах

Интерфейсы похожи на образ кассиров в кинотеатре. Вы знаете, что можете сказать им, какой фильм вы хотите посмотреть и где вы хотите сидеть. Вы знаете, что они будут просить у вас денег, и что вы можете дать им деньги. Кроме того, вы ожидаете, что в конце концов они передадут вам билет. Однако вас не волнует, как они на самом деле дадут вам билет (что они вводят в компьютер) или пойдут ли они за деньгами из другого регистра. Теперь, если вы действительно пойдете в кинотеатр, вы можете ожидать, что кассир, которого вы встретите, оправдает все ваши ожидания, а также некоторые вещи, которые каждый кассир предлагает наверху (например, небольшой разговор).

Образ кассира в вашем сознании - это интерфейс. Фактический кассир - это реализованный класс - скорее всего, подкласс «Человек».

«Разделить» что-то означает разделить, отделить или изолировать это. В связи с принципом разделения интерфейсов цель состоит в том, чтобы интерфейсы были как можно более конкретными и ориентированными на единую ответственность. Если необходимо, разделив их.

Или, как говорит Роберт К. Мартин:

«Клиенты не должны зависеть от интерфейсов, которые они не используют».

Эта проблема

Давайте посмотрим на следующий пример, чтобы увидеть, как несоблюдение этого принципа может навредить нам. Следующие вещатели событий для электронной почты и push-уведомлений реализуют интерфейс CanBroadcast, поэтому другие службы знают, что они могут отправлять уведомления с ними:

Как видите, общий интерфейс Broadcasters гарантирует, что они реализуют методы send и trackReads. Есть только одна загвоздка: PushBroadcaster не использует этот метод, потому что push-уведомления не поддерживают статус чтения в нашем случае.

Это приводит к двум проблемам:

  • В коде есть накладные расходы. Нужно прочитать реализованный метод, чтобы понять, что он не актуален для класса.
  • Если кто-то хочет изменить способ обработки отслеживания уведомлений, нужно коснуться кода, который на самом деле не заботится об отслеживании уведомлений. Я описал причину, по которой это проблема, в посте Принцип открытости и закрытости.

Решение

Мы могли бы исправить две болевые точки следующим образом:

Теперь классы электронной почты и push-уведомлений реализуют интерфейс CanBroadcast, однако интерфейс CanTrackReads реализует только почтовый вещатель.

Таким образом, нет необходимости генерировать исключения во время выполнения в ненужных методах. Это означает, что классы легче читать и, следовательно, поддерживать.

Кроме того, изменения можно вносить с большей уверенностью, потому что нужно только прикоснуться к классам, на которые действительно повлияло изменение.

И последнее, но не менее важное: потребители могут использовать новую структуру, чтобы убедиться, что они имеют дело только с релевантными типами, например. вещатели, которые позволяют отслеживать чтения.

Как выявлять нарушения

Выявить нарушения принципа разделения интерфейсов обычно несложно. Следует остерегаться, если

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

Получайте уведомления по электронной почте о новых сообщениях, подписавшись в моем блоге.