www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Мониторинг  

Какая задача мониторинга отнимает больше всего времени?

Многие системные администраторы тратят до 30% рабочего времени на рутину мониторинга. Но

 Читать далее...

Рынок труда  

Какие навыки вы хотите развивать в 2026 году?

Рынок труда меняется быстро. Еще вчера его называли рынком соискателей, а сегодня

 Читать далее...

Книжная полка  

От сисадмина до архитектора: книги, которые прокачают ваш стек в этом году

Новинки от издательства «БХВ» отличаются тем, что в них часто делается упор

 Читать далее...

Автоматизация  

Автоматизируем рутину: что реально работает?

Многие сисадмины автоматизировали что-то за последний год. Но далеко не все остались

 Читать далее...

Защита ИТ-системы  

Практическая защита: что вы внедрили и что мешает?

Какие меры безопасности реально внедрить в реальных условиях – и что не

 Читать далее...

Вопрос-ответ  

Обеспечиваем безопасную эксплуатацию базы данных

Что для вас чаще всего является причиной инцидентов с БД? Как вы

 Читать далее...

Книжная полка  

От «безопасного» Linux до Контролируемого взлома

Издательство «БХВ» продолжает радовать читателей интересными новинками и в наступившем году. Вы можете

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 13486
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 13598
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 11062
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 5926
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 6778
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 6652
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 9491
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 6099
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 6317
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 10476
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 13944
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 15397
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 17722
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 12572
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 10579
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 8788
Комментарии: 4
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 7387
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 6195
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 5817
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 6133
Комментарии: 1
Рецензия на книгу «MongoDB в действии»

 Читать далее...

Друзья сайта  

 Interface Segregation Principle. Принцип разделения интерфейсов в проектировании приложений

Архив номеров / 2024 / Выпуск №4 (257) / Interface Segregation Principle. Принцип разделения интерфейсов в проектировании приложений

Рубрика: Разработка /  Принципы проектирования

 ВИЗИТКА 



Ольга Федорова,
технический лидер «Альфа банка»

 

Interface Segregation Principle
Принцип разделения интерфейсов в проектировании приложений


Эта статья из серии «SOLID» посвящена четвертому принципу проектирования приложений – Interface Segregation или «разделения интерфейсов». Как обычно, начнем с оригинальной формулировки Роберта Мартина, которая звучит следующим образом: программные сущности не должны зависеть от методов, которые они не используют.

 

Чтобы это продемонстрировать, я хочу обратиться к реализации коллекции в языке Java. Как минимум, потому что это хороший пример того, что даже на уровне языков инженерные принципы не всегда реализованы должным образом и не надо относится к системным библиотекам как к идеалу инженерной индустрии. Знатоки JVM стека могут мне возразить, что для такой реализации были свои исторические причины, я не буду с ними спорить, но давайте посмотрим, что из этого вышло.

Для тех, кто не знаком с Java, я прикладываю картинку со структурой класса Collections, в принципе, для общего понимания его достаточно.

 

Итак, вы разрабатываете библиотеку, которая отправляет сообщения через TCP- сеть (разумеется, с использованием того, что выше, это же базовые возможности языка). Она достаточно умная, чтобы отправлять их ассинхронно, согласно приоритету, и накапливать смс в буфер, если все сразу не пролезли в сеть. Соответственно, при добавлении СМС в очередь у вас достаточно много логики, вы должны это дело залогировать, найти правильное место в очереди согласно приоритетам и т.д. Все работает, все счастливы.

В один непрекрасный день вы сталкиваетесь с необходимостью дать клиентскому коду возможность пробежаться по СМС, стоящим в очереди. Конечно же, вы не можете допустить чтобы кто-то модифицировал состояние коллекции, поэтому внутри библиотеки тихонько вызывается Collection.unmodifiedSet(), а вот уже результат вы отдаете клиентскому коду.

Что делает клиентский код? Видит метод add и воодушевленно вызывает его. Не всегда обоснованно, зачастую просто потому, что «почему бы и нет?». Однако, вместо ожидаемого результата, он встретит ошибку.

Здесь мы и вспоминаем оригинальную формулировку Interface Segregation. Суть заключается в том, чтобы клиентский код зависел только от тех частей системы, которые он реально использует. Если клиентскому коду не требуется использовать какие-то функции или возможности, то лучше вообще не предоставлять ему доступ к ним. Это позволяет избежать ненужных зависимостей и сделать систему более гибкой и поддерживаемой.

Рассмотрим другой пример и тоже из Java. Дабы у вас не сложилось предвзятое отношение к этому языку, сразу оговорюсь, что такие проблемы есть и в C#, и в других языках. Итак, интерфейс Collection:

 

Какие недостатки есть у исходного интерфейса? Как минимум, его можно было бы разделить на несколько более специализированных интерфейсов. Например:

  • методы модификации коллекции: add, addAll, clear и т.д.;
  • методы итерации и доступа: iterator, isEmpty и пр.;
  • конвертеры toArray, toStream;
  • наследование java object.

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

Давайте рассмотрим другой пример. Предположим, у нас есть интерфейс Payment с определенным набором методов. Кто-то реализует этот интерфейс, и, на первый взгляд, вся эта схема выглядит неплохо.

public interface Payment {
         
void initiatePayments();
          Object
status();
          List<Object>
getPayments();
}

public class BankPayment implements Payment {
          @Override
          public void initiatePayments() {
                   //
реализация
          }

          @Override
          public Object status() {
                   //
реализация
          }

          @Override
          public List<Object> getPayments() {
                  
// реализация
          }
}


Предположим, по мере развития программы, в какой-то момент появляется LoanPayment со своими методами, весьма похожими на те, что уже есть в Payment, за исключением небольшого отличия. И в целом, на первый взгляд, можно согласится на то, чтобы класс имплементировал интерфейс, хотя наличие Unsupported Operation уже вызывает сомнения.

public class LoanPayment implements Payment {
          @Override
          public void initiatePayments() {
                  
throw new UnsupportedOperationException("This is not
a bank payment")
;
          }

          @Override
          public Object status() {
                   //
реализация
          }

          @Override
          public List<Object> getPayments() {
                  
// реализация

          }
}

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

public interface Payment {
         
void initiatePayments();

          Object
status();

          List<Object>
getPayments();

         
void intiateLoanSettlement();

         
void initiateRePayment();
}

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

public class BankPayment implements Payment {
          @Override
          public void initiatePayments() {
                   //
реализация
          }

          @Override
          public Object status() {
                   //
реализация
          }

          @Override
          public List<Object> getPayments() {
                  
// реализация
          }

          //
Новые методы, добавленные к интерфейсу Payment
          @Override
          public void intiateLoanSettlement() {
                  
throw new UnsupportedOperationException("This is not
a loan payment"
);
          }

          @Override
          public void initiateRePayment() {
                  
throw new UnsupportedOperationException("This is not
a
loan payment");
          }

}

Это уже делает код очень неуклюжим.

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

Во-вторых, тестировать такой класс становится сложнее даже на уровне юнит-тестов.

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

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

Кроме того, это подходит под принцип open-closed, о котором мы говорили ранее. Мы не модифицируем существующий код, а расширяем его. В результате код становится более чистым и соблюдает принципы SOLID.

public interface Payment {
          Object
status();
          List<Object>
getPayments();
}

public interface Bank extends Payment {
         
void initiatePayments();
}

public interface Loan extends Payment {
         
void intiateLoanSettlement();
         
void initiateRePayment();
}

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

К слову, напомню, что наличие интерфейсов в программе само по себе это хорошая практика, потому что они уменьшают связность кода, что в свою очередь снижает риск превращения продукта в Big Ball of Mud. Да, можно сказать, что большое количество интерфейсов не есть хорошо, потому что это отнимает ресурсы памяти и все такое.

С одной стороны, это правда. Но, с другой стороны, в современном мире мы чаще страдаем не от нехватки железа, а от отсутствия общего понимания происходящего в программе спустя несколько лет активной разработки. Поэтому интерфейсы – это ключевой инструмент в поддержании чистоты и структурированности кода. А правильная организация интерфейсов (в том числе, следование принципу Interface Segregation) – это залог надежной архитектуры приложения.  

  1. Федорова О. Single Responsibility Principle. «Системный администратор». 2024. №1-2.
  2. Федорова О. Open Closed Principle. «Системный администратор». 2024. №1-2.
  3. Федорова О. Принцип подстановки Барбары Лисков, и почему наследующий класс должен дополнять, а не замещать поведение базового класса. «Системный администратор». 2024. №3.



Ключевые слова: SOLID, ISP, Interface Segregation Principle, Роберт Мартин


Подпишитесь на журнал

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru