Подтвердить что ты не робот

Лучшая практика Java: класс с только статическими методами

У меня есть приложение, в котором у меня есть класс с именем PlausibilityChecker. Этот класс имеет только статические методы, такие как checkZipcodeFormat или checkMailFormat. Я использую их в своих классах GUI для проверки ввода перед отправкой его на нижний уровень.

Это хорошая практика? Я думал, что буду использовать только статические методы, поэтому мне не нужно заботиться о передаче экземпляра в классы GUI или иметь поле экземпляра в каждом классе gui, который не ссылается на объект gui.

Я заметил, что класс Files Java NIO имеет только статические методы, поэтому я предполагаю, что это не может быть настолько ужасно неправильным.

4b9b3361

Ответ 1

Я бы сказал, что вы делаете все правильно. Помимо этого, некоторые советы для вашего служебного класса:

  • Убедитесь, что у него нет никакого состояния. Это значит, что в классе нет поля, если оно не объявлено static final. Кроме того, убедитесь, что это поле является неизменным, например, например. String s.
  • Убедитесь, что он не может быть суперклассом других классов. Сделайте класс final, чтобы другие программисты не могли его расширять.
  • Этот аргумент является дискуссионным, но вы можете объявить конструктор no-arg private, поэтому ни один другой класс не может создать экземпляр вашего класса утилиты (используя отражение или что-то подобное, но нет необходимости в том, чтобы защищать с классом). Почему вы не можете это сделать? Ну, это странный случай, когда вам нужно/нужно ввести экземпляр класса утилиты, например. через интерфейс, а не напрямую использовать его по вашему классу. Вот пример этого. Этот проект действительно странный, но может произойти (как показано в ссылке выше), но если вы не будете работать в таком случае, лучшим советом является сохранение конструктора private.

Есть много библиотек, которые предоставляют классы полезности, чтобы помочь нам программистам в нашей работе. Одним из наиболее известных является Apache Common набор библиотек. Это с открытым исходным кодом, и вы можете проверить код, чтобы узнать, как они проектируют эти классы утилит, чтобы создать ваши. (ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: я не работаю и не поддерживаю эти библиотеки, я их счастлив)

Важное примечание: Избегайте использования одноэлементного кода для вашего класса утилиты.

Ответ 2

Не беспокойтесь о подклассе или создании экземпляра. Следующие классы утилиты в JDK могут быть подклассифицированы или созданы, но никто не злоупотреблял ими за все эти годы. Люди не такие глупые.

java.beans.Beans
java.beans.PropertyEditorManager
java.lang.invoke.LambdaMetafactory
java.lang.reflect.Modifier
java.net.URLDecoder                                   ...but not URLEncoder:)
javax.management.DefaultLoaderRepository
javax.management.Query
javax.management.loading.DefaultLoaderRepository
javax.management.relation.RoleStatus
javax.print.ServiceUI
javax.swing.UIManager
javax.swing.plaf.basic.BasicBorders
javax.swing.plaf.basic.BasicGraphicsUtils
javax.swing.plaf.basic.BasicHTML
javax.swing.plaf.basic.BasicIconFactory
javax.swing.plaf.metal.MetalBorders
javax.swing.plaf.metal.MetalIconFactory
javax.swing.text.Utilities
javax.swing.text.html.HTML

Однако, как публичный API, вы хотите отключить конструктор по умолчанию, иначе на странице javadoc есть недокументированный конструктор, который неудобен и запутан. Для ваших собственных API-интерфейсов это не имеет значения, никто не заботится.

Нет причин для подавления подкласса. Если кто-то хочет подклассифицировать класс утилиты, по какой-то причине, позвольте ему. Конечно, частный конструктор будет подавлять подкласс в качестве побочного эффекта.


В java8 есть больше возможностей для проектирования -

Интерфейс со всеми статическими методами - это так же хорошо, как класс со всеми статическими методами. Для этой цели не используется ни интерфейс, ни класс, поэтому любой из них в порядке. Однако не ожидайте наследования этих статических методов в подтипах интерфейса - интерфейс статических методов не наследуется. Один плюс для использования интерфейса заключается в том, что нам не нужно подавлять конструктор по умолчанию, появляющийся на javadoc.

Интерфейс со всеми методами по умолчанию - доступ через наследование. Это интересно, но проблематично вообще (наследование работает только в нестационарном контексте). Но это может быть лучшим вариантом в некоторых проектах API, например, этот html builder API.

Ответ 3

В Java 8 теперь вы можете изменить свои статические классы утилиты на интерфейсы со статическими реализациями. Это устраняет необходимость сделать класс окончательным и предоставить частный конструктор. Это так же просто, как изменить "класс" на "интерфейс" и удалить последнее слово, если оно у вас (все интерфейсы абстрактны, поэтому они не могут быть окончательными). Поскольку методы интерфейса всегда являются общедоступными, вы можете удалить из них любую общедоступную область. Если у вас есть частный конструктор, тогда удалите его (вы не можете скомпилировать интерфейс с конструктором, так как они не могут быть созданы). Это меньше кода и выглядит чище. Вам не придется реорганизовывать какие-либо классы, которые уже используют его.

Ответ 4

Почему не должно быть хорошей практики, если у вас есть только методы, которые предоставляют "инструменты" для других классов, это нормально.

Ответ 5

Классы с только статическими методами - это общий шаблон в Java для служебных методов. Примеры в стандартной библиотеке включают Files, Collections, Executors.

Для таких классов полезности важно убедиться, что ваш класс не может быть создан, чтобы сделать цель класса понятной. Вы можете сделать это, явно объявив частный конструктор. См. Пункт 4: Для получения более подробной информации о неинстантируемости с помощью частного конструктора в "Эффективной Java" Джоша Блоха.

Ответ 6

Singleton в порядке, в зависимости от контекста.

В целях тестирования вы можете захотеть высмеять ссылки на синглеты, чтобы избежать побочных эффектов во время модульных тестов. В этом случае, вероятно, имеет смысл использовать инфраструктуру внедрения зависимостей, такую ​​как Spring, для обработки создания экземпляра и использования обычных методов, которые могут быть переопределены вместо статических методов.

Если вы все еще планируете использовать статические методы, убедитесь, что вызовы являются потокобезопасными, если они используются в многопоточном контексте. (например, дважды проверенная блокировка).