Если у вас есть класс, который наследует от двух разных классов, не означает ли это, что ваш подкласс автоматически делает (как минимум) 2 вещи, по одной от каждого суперкласса?
Я считаю, что нет разницы, если у вас есть несколько интерфейсов наследования.
Изменить: Чтобы было ясно, я считаю, что если подклассы нескольких классов нарушают SRP, то реализация нескольких интерфейсов (не маркерный или базовый интерфейс (например, Comparable)) также нарушает SRP.
Ответы:
В очень узком смысле ответ «Да»: если предположить, что ваши базовые классы или интерфейсы предназначены для одной цели, наследование их обоих создает класс с множеством обязанностей. Однако, является ли это "плохой вещью", зависит от природы классов или интерфейсов, которые вы наследуете.
Вы можете разделить ваши классы и интерфейсы на две основные группы: те, которые касаются существенной сложности вашей системы, и те, которые касаются ее случайной сложности. Если наследовать от нескольких классов "существенной сложности", это плохо; если вы наследуете один «обязательный» и один или несколько «случайных» классов, это нормально.
Например, в биллинговой системе у вас могут быть классы для представления счетов и циклов выставления счетов (они касаются существенной сложности) и классы для сохраняющихся объектов (они обращаются к случайной сложности). Если вы наследуете так
это плохо: на вас
BillingCycleInvoice
лежит смешанная ответственность, поскольку она связана с существенной сложностью системы.С другой стороны, если вы наследуете так
с вашим классом все в порядке: технически он обслуживает две проблемы одновременно, но, поскольку только одна из них важна, вы можете списать наследование случайной как «затраты на ведение бизнеса».
источник
SRP - это руководство, позволяющее избегать божьих занятий, которые являются плохими, но его также можно воспринимать слишком буквально, и проект запускает воздушный шар с кучей классов, которые действительно ничего не могут сделать без объединения нескольких вещей. Множественное наследование / множественные интерфейсы могут быть признаком того, что класс становится слишком большим, но это также может быть признаком того, что ваш фокус слишком гранулирован для выполняемой задачи и ваше решение перегружено, или оно может быть просто идеальным действительный вариант использования для множественного наследования и ваши опасения необоснованны.
Разработка программного обеспечения - это столько же искусство, сколько наука, это уравновешивание многих конкурирующих интересов. У нас есть правила, помогающие избежать того, что, как мы знаем, далеко не в одном направлении, что вызывает проблемы, но эти правила могут так же легко привести нас в такое же плохое или плохое место, как мы и пытались избежать в первую очередь.
источник
В некотором роде. Давайте сосредоточимся на основном принципе для SRP:
Многократное наследование не заставляет это, но имеет тенденцию приводить к этому. Если класс переопределяет или реализует свои базовые классы, это имеет больше причин для его изменения. Таким образом, множественное наследование интерфейса имеет тенденцию быть более проблематичным, чем наследование классов. Если два класса наследуются, но не переопределяются, то причины изменения существуют в базовых классах, а не в новом классе.
Места, где множественное наследование не нарушает SRP, - это когда все, кроме одного из базовых типов, не являются чем-то, что реализует класс, а действуют как черта, которой обладает класс. Рассмотрим
IDisposable
в C #. Вещи, которые являются одноразовыми, не имеют двух обязанностей: интерфейс просто выступает в качестве представления для классов, которые разделяют эту черту, но имеют совершенно разные обязанности.источник
Не по моему мнению. Для меня одной обязанностью является «моделирование пользователя моего приложения». Мне может понадобиться доставить эти данные через веб-сервис и сохранить их в реляционной базе данных. Я мог бы обеспечить эту функциональность, унаследовав несколько смешанных классов.
Это не значит, что у класса три обязанности. Это означает, что часть ответственности за моделирование пользователя требует поддержки сериализации и постоянства.
источник
Не за что. В Java у вас может быть интерфейс, представляющий некоторый вид предметного объекта - например, Foo. Возможно, его нужно будет сравнивать с другими объектами Foo, и поэтому он реализует Comparable (с логикой сравнения, экстернализованной в классе Comparator); может случиться так, что этот объект также должен быть Сериализуемым, чтобы его можно было транспортировать по сети; и это, возможно, должно быть Клонируемым. Таким образом, класс реализует три интерфейса, но не имеет никакой логики для их поддержки, кроме той, которая поддерживается Foo.
Тем не менее, глупо доводить SRP до крайности. Если класс определяет более одного метода, нарушает ли он SRP? Все объекты Java имеют метод toString () и метод equals (Object), что означает, что КАЖДЫЙ объект в Java отвечает как за равенство, так и за самопредставление. Это плохо?
источник
Я думаю, это зависит от того, как вы определяете ответственность. В классическом примере iostream это не нарушает SRP. IOstream отвечает за управление одним двунаправленным потоком.
После того, как вы исчерпали примитивные обязанности, вы переходите к более общим обязанностям высокого уровня, в конце концов, как вы определяете ответственность своей основной точки входа? Его обязанность должна заключаться в том, чтобы быть «главной точкой входа», а не «всем, что делает мое приложение», иначе невозможно не нарушить SRP и создать приложение.
источник