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

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

Интеграция Open Source-решений  

Open Source в облачной среде

Облачные решения становятся всё более популярными в мире. Компании стремятся использовать их для

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

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

Нейросеть вам в руки! Как использовать ИИ для автоматизации задач

Использование ИИ для автоматизации задач помогает компании получить конкурентное преимущество, поскольку объединение

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

Рынок труда  

Специалист по этическому ИИ, инженер по квантовым вычислениям или аналитик по метавселенной?

Новые тенденции в развитии ИТ могут привести к возникновению новых специальностей в

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

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

Учитесь убеждать и побеждать

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

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

Сетевая инфраструктура  

Как удаленная работа меняет подход к сетевой инфраструктуре?

С увеличением числа сотрудников, работающих из дома, организации сталкиваются с необходимостью создания

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

Мониторинг  

Какой мониторинг нужен сегодня?

По мнению экспертов ГК InfoWatch, действия сотрудников – самая распространенная причина инцидентов

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

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

Руководство для тех, кто увлечен ИИ, программированием. И дизайном

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

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

Мобильные приложения  

Искусственный интеллект в мобильных приложениях: возможности и перспективы

Обзор современных применений ИИ в мобильных приложениях, анализ перспектив развития этой технологии,

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

ИТ-образование  

Как сделать ИТ-образование эффективным?

Эксперты ИТ-отрасли отвечают на вопросы «СА». Обсуждаем ключевые аспекты для улучшения образовательных

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

Work-life balance  

Как айтишнику найти баланс между работой и личной жизнью?

Обсуждаем инструменты для эффективного управления временем, снижения уровня стресса и достижения гармонии. На

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

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

Всё самое нужное – под одной обложкой

Отличительная черта книжных новинок, выпущенных недавно издательством «БХВ» – это их универсальность. Не просто

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

ИТ-инфраструктура  

Системы мониторинга ИТ-инфраструктуры-2025

Без мониторинга ИТ-инфраструктуры не обходится ни одна компания, хотя бы потому, что

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

Открытое ПО  

Безопасность Open Source: рискуем или контролируем?

Компания «Кросс технолоджис» изучила, как используется ПО с открытым кодом в компаниях

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

Работа с нейросетью  

Скажи, есть ли у тебя AI, и я скажу, кто ты

Недавно сервис по поиску работы SuperJob выяснил, что каждый второй россиянин уже

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

03.12.2013г.
Просмотров: 4720
Комментарии: 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