Является ли высокая сплоченность синонимом принципа единой ответственности? Если нет, то чем они отличаются?
Является ли высокая сплоченность синонимом принципа единой ответственности?
Ответы (4)
Это не одно и то же.
У вас может быть очень сплоченный класс, у которого нет единственной ответственности.
Вы спросили: Если нет, то чем они отличаются?
Принцип единой ответственности
Выбросьте все, что, как вы думаете, означает этот принцип.
Роберт С. Мартин официально определяет этот принцип как:
У класса должна быть только одна причина для изменения
Большинство людей, определяющих SRP, неверны. SRP обычно неправильно объясняют как:
Класс Employee
не должен UpdateDemographics()
и SendMessage()
, это считается двумя обязанностями ... помещать SendMessage()
в класс сообщений !!
^^ Неправильно
vv справа
Роберт С. Мартин говорит
Ответственность - это не то, что «делает код». (НДЦ 2012)
Роберт С. Мартин определяет SRP как:
Любой модуль должен быть ответственным только перед одним человеком - [роль]. (НДЦ 2012)
Когда Заинтересованная сторона просит изменить сортировку данных в представлении, руководство не должно волноваться и беспокоиться о том, что алгоритмы сломаются. Потому что модуль, который обрабатывает сортировку в представлении, несет ответственность только перед заинтересованной стороной, а модуль, который обрабатывает алгоритм подсчета итоговых данных, отвечает только перед бизнес-аналитиком. Итак, когда Бизнес-аналитик просит внести изменения в алгоритм, не стоит опасаться, что View изменится.
Следовательно, модуль (единичный) должен изменяться только по одной причине: отдельное лицо - роль, для которой обслуживается этот модуль, запросило изменение.
Имея это в качестве новой основы для определения SRP, теперь вы можете применить то, что, как вы думали, было ранее SRP, и сделать определение более детальным. Никто не говорит, что весь ваш интерфейсный код должен быть объединен в один модуль, а весь внутренний код - в один модуль.
Высокая сплоченность
Представьте, что у вас есть метод decimal CalculatePayFor(Employee)
и другой метод void Pay(Employee)
.
Принадлежат ли они друг другу? Может быть служба, которая выполняет всевозможные вычисления, и может быть служба, которая не делает ничего, кроме оболочки SOAP для оплаты человеческих ресурсов. Возможно, Pay(Employee)
взывает к CalculatePayFor(Employee)
, но то, что в них есть слово Pay
, не означает, что они принадлежат друг другу!
Как мне создать сплоченность? - Нет. Сплоченность - это то, что вы наблюдаете. Что вы делаете: Не рвите на части то, что принадлежит друг другу.
Можно создать класс для каждого публичного метода, который вам нужен. У каждого класса теперь есть один общедоступный метод, и все это представляет собой четко определенный беспорядок. У вас есть классы с именами PayrollClass1
и PayrollClass2
, потому что один выполняет вычисления в одном направлении, а другой - в двух направлениях.
Некоторые языки даже выигрывают от полного отсутствия классов, а методы работают бесплатно. Нет никакой группировки методов, методы - это просто методы, которые вы можете вызывать в любое время. Все они довольно статичны.
Однако вы можете заметить, что CalculatePayFor(Employee)
и Pay(Employee)
на самом деле ОЧЕНЬ сильно связаны. Они как чертовски супружеская пара и прекрасно смотрятся вместе. Когда методы явно связаны друг с другом, вы не хотите разрывать их. Понаблюдайте за их естественным состоянием и создайте заказник. Это Поддержание высокой сплоченности. Вы не создаете это, вы это наблюдаете.
На самом деле это помогает правильное дублирование кода. Например, PayrollService.CalculatePayFor(Employee)
имеет тот же точный код, что и ReportService.CalculatePayFor(Employee)
. Это плохо? Конечно, нет. Если высшее руководство просит внести изменения в расчет заработной платы сотрудников для отчетности, это другая ответственность, чем если бы Х.Р. велит вам внести изменения в расчет для налоговых целей для фактического метода оплаты.
Подождите, он только что перепутал SRP и Cohesion? Нет, но я рад, что ты понял путаницу. Что, если ReportService проникнет в класс PayrollService и использует его метод? Затем, когда он изменяется для законных целей оплаты, все отчеты меняются ... но руководство этого не хотело !!! Таким образом, поскольку Cohesion заставляет методы оставаться в своих классах, а SRP заставляет модули оставаться в пределах одного приложения, ReportService вынужден копировать / вставлять метод из класса PayrollService. Теперь они могут меняться независимо друг от друга.
Но что, если вы этого не хотите? Что ж, в коде есть много мест, где исключено дублирование. Но чаще всего алгоритмы придерживаются самих себя и изменяются независимо от зависимостей. Даже если это означает дублирование. Это просто зависит от того, что нужно. Но разделение проблем, единоличная ответственность, сплоченность и СУХОЙ (не повторяйся) - это разные идеи.
Примечание: СУХОЙ не означает, что никогда не будет дублирования. Как я уже упоминал: много раз у вас может быть дублированный код, потому что бизнес-правила схожи для разных задач и имеют разные причины для изменения.
Payroll.CalculatePay
и Report.CalculatePay
должны сильно отличаться. Но вы обнаружите, что, хотя вычисления глубокого ядра всегда должны быть одинаковыми, материалы более высокого уровня о том, как он организует, группирует, сортирует, фильтрует и преобразует эти данные, будут различаться между ними. В этом смысле ReportService
будет вызывать PayrollMicroService
для получения основных деталей. Но каждая служба будет преобразовывать эти данные по-своему. Просто чтобы успокоить там все опасения :)
- person Suamere; 27.09.2020
Это не синоним. SRP (принцип единой ответственности) - это когда вы гарантируете, что у ваших классов будет только одна ответственность. Конечно, это увеличивает сплоченность ваших классов.
Но вы можете иметь высокую сплоченность, не следуя букве SRP.
Вот хороший источник по этому поводу.
По словам Роберта Мартина, собственными словами Роберта Мартина,
Если вы подумаете о [SRP], то поймете, что это просто еще один способ определения сплоченности и сцепления. Мы хотим увеличить взаимосвязь между вещами, которые меняются по одним и тем же причинам, и мы хотим уменьшить взаимосвязь между теми вещами, которые меняются по разным причинам.
См. Также: Разница между принципом единой ответственности и разделением проблем.