Принцип единой ответственности
(«У каждого класса должна быть только одна ответственность; иными словами, у каждого класса должна быть одна и только одна причина для изменения»)
Я не согласен. Я думаю, что метод должен иметь только одну причину для изменения, и все методы в классе должны иметь логическое отношение друг к другу , но сам класс может фактически делать несколько (связанных) вещей.
По моему опыту, этот принцип слишком часто применяется слишком усердно, и в результате вы получаете множество крошечных классов с одним методом. Оба проворных магазина, в которых я работал, сделали это.
Представьте себе, если бы у создателей .Net API был такой менталитет: вместо List.Sort (), List.Reverse (), List.Find () и т. Д. У нас были бы классы ListSorter, ListReverser и ListSearcher!
Вместо того, чтобы больше спорить с SRP (что само по себе не страшно в теории) , я поделюсь некоторыми из моих давних анекдотических событий:
В одном месте, где я работал, я написал очень простое средство определения максимального потока, которое состояло из пяти классов: узла, графа, создателя графа, решателя графа и класса, чтобы использовать создателя / решателя графа для решения задачи. реальная проблема. Ни один из них не был особенно сложным или длинным (решатель был самым длинным в ~ 150 строк). Однако было решено, что у классов слишком много «обязанностей», поэтому мои коллеги приступили к рефакторингу кода. Когда они были сделаны, мои 5 классов были расширены до 25 классов, чьи строки кода были более чем в три раза больше, чем они были изначально. Поток кода больше не был очевиден, как и цель новых юнит-тестов; Теперь мне было трудно понять, что сделал мой собственный код.
В то же время почти у каждого класса был только один метод (его единственная «ответственность»). Следование потоку внутри программы было почти невозможно, и большинство юнит-тестов состояло из проверки того, что этот класс вызывал код из другого класса , оба из которых были для меня загадкой. Были буквально сотни классов, в которых (ИМО) должны были быть только десятки. Каждый класс делал только одну «вещь» , но даже с соглашениями об именах, такими как «AdminUserCreationAttemptorFactory» , было трудно определить связь между классами.
В другом месте (где также существовал менталитет « класс должен иметь только один метод» ), мы пытались оптимизировать метод, который занимал 95% времени во время определенной операции. После некоторой (довольно глупой) оптимизации его я переключил свое внимание на то, почему его называют баджиллионным разом. Он вызывался в цикле в классе ... чей метод вызывался в цикле в другом классе ... который также вызывался в цикле ...
В общей сложности было пять уровней петель, разбросанных по 13 классам (серьезно). То, что на самом деле делал какой-то один класс, было невозможно определить, просто взглянув на него - вам пришлось нарисовать мысленный график того, какие методы он вызывал, какие методы вызывали эти методы и так далее. Если бы все это было объединено в один метод, то было бы всего около 70 строк с нашим проблемным методом, вложенным в пять сразу очевидных уровней циклов.
Моя просьба о реорганизации этих 13 классов в один класс была отклонена.