Единая ответственность (SRP) против «Скажи, не спрашивай» (TDA)?

Я понимаю, что многие принципы дизайна в некоторых случаях противоречат друг другу. Итак, мы должны взвесить их и посмотреть, какой из них более выгоден. До сих пор я знал о принципе SRP и делал множество своих проектов исключительно на его основе, но внутренне я иногда чувствовал себя не так, следуя этому принципу. Теперь я узнал о TDA, и я почувствовал, что получил больше поддержки :)

SRP: - Объект должен беспокоиться о себе, а не о ком-либо другом

TDA: - Поведение (которое зависит только от состояния объекта) должно сохраняться внутри самого объекта.

Пример: - У меня есть разные формы, такие как прямоугольник, квадрат, круг и т. д. Теперь мне нужно вычислить площадь.

Мой дизайн до сих пор: - Я следовал SRP, где у меня был класс AreaCalculatorService, который будет запрашивать состояние формы и вычислять площадь. Причина этого дизайна заключалась в том, что форма не должна беспокоить расчет площади, поскольку это не ответственность за форму. Но в идеале я привык думать, что код вычисления области должен находиться под каждой формой, как если бы в конце строки, если появляется новая форма, мне нужно изменить класс AreaCalculatorService (который нарушает принцип открытия для расширения и закрытия для изменения (OECM)). Но всегда отдавал предпочтение SRP. Это кажется неправильным

Миф сломан (по крайней мере, мой): - С TDA, похоже, мое ощущение было правильным, когда я не должен спрашивать о состоянии объекта, но должен сказать форме, чтобы вычислить его площадь. Хотя это нарушит принцип SRP, но будет поддерживать принцип OECM. Как я уже сказал, принципы дизайна иногда конфликтуют друг с другом, но я считаю, что там, где поведение полностью зависит от состояния объекта, поведение и состояние должны быть вместе.

Другой пример: - скажем, я должен рассчитать зарплату всех отделов всех сотрудников в организации, тогда мы должны следовать SRP, где SalaryCalculatorService будет зависеть от отдела и сотрудников.

Он спросит зарплату каждого сотрудника, а затем произведет суммирование по всем зарплатам. Итак, здесь я прошу состояние сотрудника, но все же не нарушаю TDA. CalcSalary не зависит только от заработной платы каждого сотрудника.

Сообщите мне, верна ли моя интерпретация обоих этих принципов, где я должен следовать TDA в первом случае, а SRP - во втором?


person emilly    schedule 05.11.2016    source источник
comment
Каковы обязанности фигур? Об этом сложно говорить на пустом месте. Ваши примеры слишком малы.   -  person Javier    schedule 05.11.2016
comment
это может быть что угодно, что логически образует форму типа getName(), сохраняя ее состояние и т. д.   -  person emilly    schedule 05.11.2016
comment
Область явно является частью интерфейса фигур. Как бы вы вообще реализовали это внешне? С линиями или кривыми? Здесь нет нарушения SRP и это определенно TDA.   -  person Javier    schedule 05.11.2016
comment
Я хотел проанализировать другой пример, но он недостаточно конкретизирован. Я не очень понимаю анализируемую проблему. Почему бы вам не создать настоящую библиотеку для реальной проблемы, опубликовать ее где-нибудь, а затем обсудить ее дизайн? Или выберите существующую библиотеку.   -  person Javier    schedule 05.11.2016
comment
There's no SRP violation here and it's definitely TDA.. Я считаю, что здесь есть нарушение SRP. В истинном смысле «единственная ответственность» означает, что для изменений должна быть единственная причина. Единственная ответственность за форму - сохранить состояние объекта, ничего больше (например, расчет площади).   -  person emilly    schedule 06.11.2016
comment
Площадь фигуры - это четко определенная формула, поэтому, если ваш код является правильной формулой, вам не придется менять класс (кроме случаев, когда вы меняете внутреннее представление фигуры, например, сохраняя radius вместо diameter).   -  person Phil1970    schedule 15.12.2016


Ответы (1)


Я думаю, что ваше понимание TDA правильное. Проблема заключается в SRP, по моему опыту, это наиболее неправильно понимаемый принцип SOLID. SRP говорит, что у одного класса должна быть только одна причина для изменения. Часть «Причина изменения» часто путают с «у нее должна быть только одна ответственность», поэтому «она должна делать только одну вещь». Нет, это не так.
«Причина изменения» полностью зависит от контекста приложения, в котором находится класс. В частности, это зависит от субъектов, которые взаимодействуют с программным обеспечением и которые в будущем могут запрашивать изменения.
Действующими лицами могут быть: покупатель, который платит за программное обеспечение, обычные пользователи и некоторые суперпользователи. Администраторы баз данных, которые будут управлять базой данных приложения, или ИТ-отдел, который обслуживает оборудование, на котором работает приложение. После того, как вы перечислили всех субъектов вокруг вашего программного обеспечения, чтобы следовать тому, что говорит SRP, вы должны написать свой класс таким образом, чтобы он имел только одну единственную ответственность, поэтому только запросы от одного актора могут потребовать некоторых изменений в вашем классе. .
Итак, я думаю, вы должны следовать TDA, помещая данные и поведение, использующие эти данные, в один и тот же объект. Таким образом, вы можете управлять отношениями между объектами, сообщая им, что делать, вместо того, чтобы запрашивать данные, уменьшая связывание и достигая лучшей инкапсуляции.
SRP, как описано выше, поможет вам решить, какое поведение следует вкладывать в один объект, а не в Еще один.

person Paolo Laurenti    schedule 06.11.2016
comment
Помимо субъектов, которые являются людьми, вы можете также рассмотреть целевые приложения. Например, вам не нужна функция Draw непосредственно в фигуре, поскольку это затруднит повторное использование общего кода, если вы перейдете на другую технологию (например, Windows, Console, Web, Open GL, Direct X ...) . - person Phil1970; 15.12.2016