В чем разница между SRP и ISP в SOLID? (Принцип единой ответственности и принцип разделения интерфейса)

Чем SOLID «Принцип разделения интерфейса» отличается от «Принципа единой ответственности» ?

запись в Википедии для SOLID говорит, что

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

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

Мне что-то не хватает, или ISP как бы дублирует SRP? Если нет, то что означает ISP, а SRP - нет?


comment
Возможный дубликат для stackoverflow.com/questions/8099010/   -  person Michael Freidgeim    schedule 13.04.2013
comment
Я полагаю, технически, но этот вопрос, ИМХО, лучше написан, а ответы более конкретизированы.   -  person Sled    schedule 14.04.2013
comment
Это одно и то же, но это не то же самое, что говорить о принципах ТВЕРДЫХ, чем о принципах ПРОДАНО. Нам нужен был еще один символ, чтобы создать напыщенное слово.   -  person Cequiel    schedule 07.04.2020
comment
@Cequiel, аббревиатура была создана спустя годы после того, как были опубликованы пять принципов, а аббревиатура была создана другим человеком (Майкл Фезерс), чем принципы (Боб Мартин).   -  person jaco0646    schedule 17.06.2020


Ответы (4)


SRP сообщает нам, что у вас должна быть только одна ответственность в модуле.

Интернет-провайдер говорит нам, что вы не должны быть вынуждены сталкиваться с тем, что вам действительно нужно. Если вы хотите использовать метод print() из интерфейса I, вам не нужно создавать для этого класс SwimmingPool или DriveThru.

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

Все это пришло из

Интернет-провайдер был впервые использован и сформулирован Робертом К. Мартином, когда он консультировал Xerox. Xerox создала новую систему печати, которая могла выполнять множество задач, таких как сшивание печатных листов и отправка факсов. Программное обеспечение для этой системы создавалось с нуля и успешно справлялось со своими задачами. По мере роста программного обеспечения внесение изменений становилось все труднее и труднее, так что даже самое маленькое изменение занимало цикл повторного развертывания до часа. Это делало практически невозможным продолжение разработки. Проблема дизайна заключалась в том, что один основной класс Job использовался почти для всех задач. Каждый раз, когда нужно было выполнить задание на печать или сшивание, вызывается какой-либо метод в классе Job. В результате получился огромный или «толстый» класс с множеством методов, специфичных для множества различных клиентов. Из-за этой конструкции задание сшивания будет знать обо всех методах задания печати, даже если они не нужны.

so

Решение, предложенное Мартином, сегодня называется принципом разделения интерфейсов. Применительно к программному обеспечению Xerox уровень интерфейсов между классом Job и всеми его клиентами был добавлен с использованием принципа инверсии зависимостей. Вместо одного большого класса Job был создан интерфейс Staple Job или интерфейс Print Job, который будет использоваться классами Staple или Print соответственно, вызывая методы класса Job. Поэтому для каждого задания был создан один интерфейс, и все они были реализованы классом Job.

@ http://en.wikipedia.org/wiki/Interface_segregation_principle#Origin

person devoured elysium    schedule 17.01.2013
comment
Хм, единственное различие, которое я вижу в вашем сообщении, - это "If you want to use a print() method from interface I, you shouldn't have to instantiate a SwimmingPool or a DriveThru class for that.", которое, честно говоря, очень похоже на Вы хотели банан, но получили гориллу, держащую банан и все джунгли.. Вы хотите сказать, что комментарий банана - это пересказ интернет-провайдера? - person Sled; 18.01.2013
comment
Вы часто видите плохо спроектированный код, в котором для использования какой-либо функции вы должны сначала включить ведение журнала, затем включить службы A, B и C, в то время как все, что вам нужно было сделать, это вычислить площадь многоточия, которая то, что вы ожидаете, не потребуют всей этой суеты. - person devoured elysium; 18.01.2013
comment
Вы можете дать мне источник этой статьи? - person Daniel Kaplan; 18.01.2013
comment
Правильно или ошибочно, я проголосовал против, поскольку считаю, что ответ SWeko намного мощнее и легче для понимания. - person AJP; 27.09.2018

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

С другой стороны, ISP заботится о том, как следует использовать модуль, имеет ли смысл потреблять только часть модуля, игнорируя при этом некоторые аспекты.

Примером кода, который сохраняет дух или SRP, но может нарушить работу ISP, является паттерн Фасад. У него единственная ответственность: «обеспечение упрощенного доступа к более крупной подсистеме», но если лежащая в основе подсистема должна раскрыть совершенно разные взгляды, это действительно нарушит работу ISP.

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

person SWeko    schedule 17.01.2013

Роберт Мартин написал следующее в Твиттере 16 мая 2018 г.

ISP можно рассматривать как аналог SRP для интерфейсов; но это нечто большее. Интернет-провайдер обобщает: «Не полагайтесь на большее, чем вам нужно». SRP обобщает так: «Собирайте воедино вещи, которые меняются по одним и тем же причинам и в одно и то же время».

Представьте себе класс стека с push и pop. Представьте себе клиента, который только подталкивает. Если этот клиент зависит от интерфейса стека, это зависит от pop, в котором он не нуждается. SRP не отделяет push от pop; Провайдер бы.

person jaco0646    schedule 09.03.2019
comment
С другой стороны, Марк Симанн считает, что SRP и ISP достаточно близки быть избыточным. - person jaco0646; 09.03.2019

SRP и ISP в конечном итоге сводятся к одному и тому же. Реализация любого из них требует разделения классов или интерфейсов.

Однако есть отличия по другим направлениям.

  1. Нарушение SRP может иметь далеко идущие последствия для всей структуры проекта, приводя к плохой ремонтопригодности, повторному использованию и, конечно же, к низкой когезии и связанности.
  2. SRP влияет как на поведенческие, так и на структурные компоненты структуры объекта.
  3. Перепроектирование с нарушением SRP требует более глубокого анализа, требует целостного рассмотрения различных компонентов дизайна.

Нарушение ISP в основном связано с плохой читабельностью (и, в некоторой степени, низкой связностью). Но влияние на обслуживание и повторное использование кода гораздо менее зловещее, чем у SRP.

Более того, рефакторинг кода для соответствия ISP, кажется, всего лишь структурным изменением.

См. Также мой блог для SRP и Интернет-провайдер

person aknon    schedule 18.12.2013
comment
Я пришел к выводу, что SRP - это одна ответственность в домене, тогда как ISP - это одно поведение. Таким образом, в библиотеке, имеющей один класс для Books и один для Movies, это SRP, но тогда getDueDate() и getMexRenewal(), являющиеся их собственным интерфейсом (например, Rentable) из getId() (например, Identifiable), являются ISP, даже если все классы Rentable также будут Identifiable . Это почти как если бы определение атомарного или отдельного для интерфейсов отличается от определения для классов. - person Sled; 18.12.2013
comment
Формального определения «атомарного» или «отдельного» не существует. В этом отношении конструктивные соображения для создания класса такие же, как и для интерфейса. - person aknon; 19.12.2013
comment
Будет ли неправильно сказать, что методы интерфейса определяют ответственность реализующего класса? Так должно быть, иначе есть некоторые переопределенные методы интерфейса, имеющие реализацию «NIL» в реализованном классе. Проще говоря, методы интерфейса (вместе взятые) определяют «атомарное» поведение типа. Классовое «атомарное» поведение или так называемая «ответственность» - это совокупность многих таких поведений. (И, конечно же, для не финального класса все общедоступные методы должны быть заменены различными реализациями) - person aknon; 19.12.2013
comment
In that respect the design considerations for building a class are the same as that of interface. Я не согласен, я считаю, что в чистом коде объем ответственности интерфейса намного уже, чем у всего класса. Вы найдете интерфейс, который определяет единственный getId() метод, но вы никогда не найдете класс с только методом getId(). Интерфейсы обычно имеют более узкую область применения. - person Sled; 20.12.2013
comment
Да, безусловно. Интерфейсы просто определяют поведение юнита. Поведение нескольких юнитов может быть одной обязанностью класса. - person aknon; 20.12.2013
comment
Этот комментарий, вероятно, лучший ответ на вопрос, почему и чем отличаются SRP и ISP. - person Sled; 20.12.2013
comment
Да, но есть еще один важный повод для беспокойства. Как определить ответственность класса ... Попытки найти объективный ответ выявляют некоторые тонкие различия - person aknon; 21.12.2013
comment
Есть ли сообщение в блоге, которое более точно определяет поведение и ответственность подразделения? - person Sled; 22.12.2013
comment
Не уверен, что это может быть полезно: design- Princip-pattern.blogspot.in/2013/12/ - person aknon; 23.12.2013