Пару месяцев назад я начал работать над новым проектом, и при прохождении кода меня поразило количество используемых статических методов. В collectionToCsvString(Collection<E> elements)
них хранятся не только служебные методы , но и множество бизнес-логики.
Когда я спросил парня, ответственного за обоснование этого, он сказал, что это был способ избежать весенней тирании . В этом процессе мышления что-то происходит: для реализации метода создания клиентской квитанции у нас может быть услуга
@Service
public class CustomerReceiptCreationService {
public CustomerReceipt createReceipt(Object... args) {
CustomerReceipt receipt = new CustomerReceipt();
// creation logic
return receipt;
}
}
Теперь парень сказал, что ему не нравится, когда Spring управляет ненужными классами, в основном потому, что он накладывает ограничение на то, что клиентские классы должны быть самими компонентами Spring. В конце концов мы имеем все, что управляется Spring, что в значительной степени заставляет нас работать с объектами без состояния процедурным способом. Более или менее то, что указано здесь https://www.javacodegeeks.com/2011/02/domain-driven-design-spring-aspectj.html
Таким образом, вместо приведенного выше кода, он имеет
public class CustomerReceiptCreator {
public static CustomerReceipt createReceipt(Object... args) {
CustomerReceipt receipt = new CustomerReceipt();
// creation logic
return receipt;
}
}
Я мог бы спорить о том, чтобы избегать Spring, когда это возможно, при управлении нашими классами, но я не вижу преимущества в том, чтобы все было статичным. Эти статические методы также не сохраняют состояния, поэтому тоже не очень OO. Я чувствовал бы себя более комфортно с чем-то, как
new CustomerReceiptCreator().createReceipt()
Он утверждает, что статические методы имеют некоторые дополнительные преимущества. А именно:
- Легче читать. Импортируйте статический метод, и нам нужно заботиться только о действии, а не о том, какой класс его выполняет.
- Очевидно, это метод, свободный от вызовов БД, поэтому с точки зрения производительности он дешев; и это хорошая вещь, чтобы прояснить это, так что потенциальный клиент должен пойти в код и проверить это.
- Проще писать тесты.
Но я просто чувствую, что с этим что-то не так, поэтому я хотел бы услышать об этом еще несколько опытных разработчиков.
Итак, мой вопрос: каковы потенциальные подводные камни этого способа программирования?
источник
static
Метод , который вы иллюстрирующие выше просто обычный фабричный метод. Создание фабричных методов статичными является общепринятым соглашением по ряду веских причин. Уместен ли здесь заводской метод, это другой вопрос.Ответы:
Какая разница между
new CustomerReceiptCreator().createReceipt()
аCustomerReceiptCreator.createReceipt()
? Почти нет. Единственным существенным отличием является то, что в первом случае синтаксис значительно более неловкий. Если вы следуете первому, полагая, что каким-то образом избегая статических методов, ваш код станет лучше, вы ошибаетесь. Создание объекта просто для вызова одного метода является статическим методом с тупым синтаксисом.То, что все меняется, - это когда ты вводишь,
CustomerReceiptCreator
а неnew
вводишь. Давайте рассмотрим пример:Давайте сравним эту версию статического метода:
Преимущество статической версии состоит в том, что я могу легко рассказать вам, как она взаимодействует с остальной частью системы. Это не так. Если я не использовал глобальные переменные, я знаю, что остальная часть системы не изменилась. Я знаю, что никакая другая часть системы не может влиять на получение здесь. Если я использовал неизменяемые объекты, я знаю, что порядок не изменился, и createReceipt является чистой функцией. В этом случае я могу свободно перемещать / удалять / и т.д. этот вызов, не беспокоясь о случайных непредсказуемых эффектах в других местах.
Я не могу сделать такие же гарантии, если я ввел
CustomerReceiptCreator
. Это может иметь внутреннее состояние, которое изменяется вызовом, на меня может повлиять или изменить другое состояние. Могут быть непредсказуемые отношения между операторами в моей функции, так что изменение порядка приведет к неожиданным ошибкам.С другой стороны, что произойдет, если
CustomerReceiptCreator
вдруг понадобится новая зависимость? Допустим, нужно проверить флаг функции. Если бы мы делали инъекцию, мы могли бы сделать что-то вроде:Тогда мы закончили, потому что вызывающий код будет введен с,
CustomerReceiptCreator
который будет автоматически введенFeatureFlags
.Что если бы мы использовали статический метод?
Но ждать! код вызова также должен быть обновлен:
Конечно, это все еще оставляет вопрос о том, откуда он
processOrder
беретсяFeatureFlags
. Если нам повезет, тропа заканчивается здесь, если нет, то необходимость проходить через FeatureFlags продвигается дальше вверх по стеку.Здесь есть компромисс. Статические методы, требующие явной передачи зависимостей, что приводит к увеличению объема работы. Внедренный метод сокращает объем работы, но делает зависимости неявными и, следовательно, скрытыми, что затрудняет анализ кода.
источник