Принцип единой ответственности основан на принципе высокой сплоченности. Разница между ними заключается в том, что у очень сплоченных классов есть набор обязанностей, которые тесно связаны, в то время как у классов, придерживающихся SRP, есть только одна ответственность.
Но как нам определить, обладает ли определенный класс набором обязанностей и, следовательно, является ли он очень сплоченным, или же он несет только одну ответственность и, следовательно, придерживается ПСП? Другими словами, не является ли это более или менее субъективным, поскольку некоторые могут считать класс очень гранулированным (и, как таковые, будут считать, что класс придерживается SRP), в то время как другие могут считать его недостаточно детализированным?
design-patterns
single-responsibility
cohesion
user1483278
источник
источник
Ответы:
Почему да, это очень субъективно, и это предмет многих горячих, краснолицых дебатов, в которые попадают программисты.
На самом деле нет единственного ответа, и ответ может измениться, поскольку ваше программное обеспечение становится более сложным. То, что когда-то было единственной четко определенной задачей, может в конечном итоге стать множеством плохо определенных задач. Это всегда загвоздка. Как вы выбираете правильный способ разделить программу на задачи?
О единственном совете, который я могу дать, это: используйте ваше (и ваших коллег) лучшее суждение. И помните, что ошибки (как правило) могут быть исправлены, если вы поймете их достаточно скоро.
источник
Боб Мартин (дядя Боб), который создал принципы SOLID, первым из которых является SRP , говорит об этом (я перефразирую, не могу вспомнить реальные слова):
Если у этого есть больше чем одна причина, это не придерживается SRP.
источник
Я могу дать вам несколько практических правил.
источник
Принципы единой ответственности гласят, что у каждого программного модуля должна быть только одна причина для изменения. В недавней статье дядя Боб объяснил «причину перемен»,
Далее он объяснил концепцию на примере ЗДЕСЬ .
источник
Чтобы ответить на это, сделайте шаг назад и рассмотрите намерение принципа единой ответственности. Почему это рекомендуемый принцип дизайна в первую очередь?
Цель этого принципа состоит в том, чтобы «разделить» кодовую базу, чтобы код, относящийся к одной «ответственности», был изолирован в одном блоке. Это облегчает поиск и понимание кода, и, что более важно, это означает, что изменения в «ответственности» будут влиять только на одну единицу кода.
То, что вам абсолютно никогда не нужно в системе, - это когда один маленький шанс приводит к сбою или изменению поведения какой-то другой явно не связанной части кода. SRP помогает выявлять ошибки и изменения.
Так в чем же тогда «ответственность»? Это то, что может измениться независимо от других изменений. Допустим, у вас есть программа, которая может сохранить некоторые настройки в файл конфигурации XML и прочитать их обратно из файла. Это одна ответственность, или «загрузить» и «сохранить» две разные обязанности? Любое изменение формата или структуры файла потребует изменения как логики загрузки, так и сохранения. Поэтому это единственная ответственность, которая должна быть представлена одним классом. Теперь рассмотрим приложение, которое может экспортировать некоторые данные в формат CVS, Excel и XML. В этом случае легко представить, что один формат может измениться, не влияя на другой. Если вы решите изменить разделитель в формате CVS, это не должно повлиять на вывод в Excel.
источник
ОО говорит, что классы - это группировка данных и функциональность. Это определение оставляет много места для субъективной интерпретации.
Мы знаем, что классы должны быть четко и легко определены. Но чтобы определить такой класс, мы должны иметь четкое представление о том, как класс вписывается в общий дизайн. Без требований типа водопада, которые, как это ни парадоксально, считаются антишаблоном ... этого трудно достичь.
Мы можем реализовать дизайн класса с архитектурой, которая работает в большинстве случаев, например, MVC. В приложениях MVC мы предполагаем, что у нас есть только данные, пользовательский интерфейс и требование к ним для общения.
С базовой архитектурой легче выявлять случаи нарушения единых правил ответственности. EG Передача экземпляра пользовательского элемента управления модальному.
источник
Просто для обсуждения я приведу класс от JUCE под названием AudioSampleBuffer . Теперь этот класс существует для хранения фрагмента (или, возможно, довольно длинного фрагмента) аудио. Он знает, что число каналов, количество выборок (на канал), кажется, соответствует 32-разрядному IEEE-плавающему, вместо того, чтобы иметь переменное числовое представление или размер слова (но это не проблема для меня). Существуют функции-члены, которые позволяют вам получать numChannels или numSamples и указатели на любой конкретный канал. Вы можете сделать AudioSampleBuffer длиннее или короче. Я предполагаю, что первые нулевые буферы буферизируют, а последние усекают.
Есть несколько закрытых членов этого класса, которые используются для выделения пространства в специальной куче, которую использует JUCE.
Но это то, чего не хватает в AudioSampleBuffer (и я несколько раз обсуждал это с Жюлем): член вызвал
SampleRate
. Как это могло пропустить это?Единственная ответственность, которую AudioSampleBuffer должен выполнить, состоит в том, чтобы адекватно представлять физическое аудио, которое слышит тот, который представляют его образцы. Когда вы вводите AudioSampleBuffer из чего-то, что читает звуковой файл или из потока, есть дополнительный параметр, который вы должны получить и передать его вместе с AudioSampleBuffer в методы обработки (скажем, это фильтр), которые должны знать частоту дискретизации или, в конце концов, к методу, который воспроизводит буфер для прослушивания (или передает его в другое место). Без разницы.
Но то, что вам нужно сделать, это продолжать передавать этот SampleRate, который присущ конкретному аудио, живущему в AudioSampleBuffer, везде и всюду. Я видел код, в котором константе 44100.0f была передана функция, потому что программист, похоже, не знал, что еще делать.
Это пример невыполнения единой обязанности.
источник
Исходя из того, что вы сказали, можно сделать конкретный путь - высокая сплоченность ведет к единственной ответственности, которую вы можете измерить. Максимальный связный класс имеет все поля, используемые во всех методах. Хотя максимальный связный класс не всегда возможен и не желателен, все же лучше достичь этого. Имея эту цель разработки класса, довольно легко сделать вывод, что в вашем классе не может быть много методов или полей (некоторые говорят, что самое большее 7).
Другой способ - из чистых основ ООП - модели после реальных объектов. Намного легче увидеть ответственность реальных объектов. Однако, если реальный объект слишком сложен, разбейте его на несколько контактирующих объектов, каждый из которых несет свою ответственность.
источник