web-dev-qa-db-fra.com

Java bonne pratique: classe avec uniquement des méthodes statiques

J'ai une application où j'ai une classe appelée PlausibilityChecker. Cette classe n'a que des méthodes statiques, comme checkZipcodeFormat ou checkMailFormat. Je les utilise dans mes classes d'interface graphique pour vérifier l'entrée avant de l'envoyer à la couche inférieure.

Est-ce une bonne pratique? Je pensais utiliser uniquement des méthodes statiques afin d'éviter de passer d'une instance aux classes de l'interface graphique ou d'avoir un champ d'instance dans chaque classe d'interface graphique qui ne fait pas référence à un objet d'interface graphique.

J'ai remarqué que la classe Files de Java NIO n'a que des méthodes statiques, donc je suppose que cela ne peut pas être aussi horriblement faux.

38
user3629892

Je dirais que vous le faites bien. En dehors de cela, quelques conseils pour votre classe utilitaire:

  • Assurez-vous qu'il n'a pas d'état. C'est-à-dire qu'il n'y a pas de champ dans la classe à moins qu'il soit déclaré static final. Assurez-vous également que ce champ est immuable, par exemple. Strings.
  • Assurez-vous qu'il ne peut pas s'agir d'une super classe d'autres classes. Créez la classe final afin que les autres programmeurs ne puissent pas l’étendre.
  • Celui-ci est discutable, mais vous pouvez déclarer un constructeur no-arg private, afin qu'aucune autre classe ne puisse créer une instance de votre classe d'utilitaires (utiliser réflexion ou quelque chose de similaire fera l'affaire, mais il n'est pas nécessaire d'utiliser cette protection. avec la classe). Pourquoi tu ne peux pas faire ça? Eh bien, c’est le cas étrange dans lequel vous souhaitez/devez injecter une instance de la classe d’utilitaires, par exemple. via une interface plutôt que de l’utiliser directement avec votre classe. en voici un exemple . Cette conception est vraiment étrange mais peut arriver (comme le montre le lien ci-dessus), mais si vous ne courez pas dans ce cas, le meilleur conseil est de garder le constructeur private.

Il y a beaucoup de bibliothèques qui fournissent des classes d'utilitaires afin de nous aider les programmeurs avec notre travail. L'un des plus connus est Apache Common ensemble de bibliothèques. C'est open source et vous pouvez vérifier le code pour voir comment ils conçoivent ces classes d'utilitaires afin de créer les vôtres. (CLAUSE DE NON-RESPONSABILITÉ: je ne travaille pas et ne supporte pas ces bibliothèques, je suis un utilisateur heureux d'eux)

Remarque importante: Évitez d'utiliser un singleton pour votre classe d'utilitaire .

41
Luiggi Mendoza

Dans Java 8, vous pouvez maintenant modifier vos classes d’utilitaires statiques en interfaces avec des implémentations statiques. Ceci élimine la nécessité de rendre la classe finale et de fournir un constructeur privé. C’est aussi simple que de changer de classe. 'interface' et en supprimant le mot final si vous en avez (toutes les interfaces sont abstraites et ne peuvent donc pas être finales). Comme les méthodes d'interface sont toujours publiques, vous pouvez en supprimer toute la portée publique. Si vous avez un constructeur privé, supprimez-le. de même (vous ne pouvez pas compiler une interface avec un constructeur car ils ne peuvent pas être instanciés). C'est moins de code et plus net, vous n'avez pas à refactoriser les classes qui l'utilisent déjà.

13
afenkner

Ne vous inquiétez pas des sous-classes ou des instanciations. Les classes d'utilitaires suivantes dans JDK peuvent être sous-classées ou instanciées, mais personne ne les a mal utilisées pendant toutes ces années. Les gens ne sont pas si stupides.

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

Cependant, en tant qu'API publique, vous souhaitez supprimer le constructeur par défaut, sinon la page javadoc contient un constructeur non documenté qui est maladroit et déroutant. Pour vos propres API internes, peu importe, personne ne s'en soucie.

Il n'y a aucune raison de supprimer le sous-classement. Si quelqu'un veut sous-classer une classe d'utilitaires, pour une raison quelconque, laissez-le. Bien entendu, le constructeur privé supprimera les sous-classes en tant qu'effet secondaire.


En Java8, il y a plus de possibilités de conception à considérer -

Une interface avec toutes les méthodes statiques - c'est aussi bien qu'une classe avec toutes les méthodes statiques. Ni l'interface ni la classe n'est conçue à cette fin, donc l'une ou l'autre est OK. Cependant, ne vous attendez pas à hériter de ces méthodes statiques dans les sous-types de l'interface - les méthodes statiques d'interface ne peuvent pas être héritées. Un des avantages de l’utilisation d’interface est qu’il n’est pas nécessaire de supprimer l’apparition du constructeur par défaut sur javadoc.

Une interface avec toutes les méthodes par défaut - accessible via l'héritage. C'est intéressant mais problématique en général (l'héritage ne fonctionne que dans un contexte non statique). Mais cela pourrait être une meilleure option dans certaines conceptions d'API, par exemple, cette API constructeur HTML .

4
ZhongYu

Pourquoi ne serait-ce pas une bonne pratique si vous avez juste des méthodes qui fournissent des "outils" à d'autres classes, c'est très bien.

1
Mirko

Les classes comportant uniquement des méthodes statiques constituent un modèle courant dans Java pour les méthodes utilitaires. Les exemples de la bibliothèque standard incluent Fichiers , Collections et - exécuteurs .

Pour de telles classes d'utilitaires, il est conseillé de s'assurer que votre classe ne peut pas être instanciée, afin de clarifier l'intention de la classe. Vous pouvez le faire en déclarant explicitement un constructeur privé. Voir Rubrique 4: Imposer la non-instabilité à un constructeur privé dans "Effective Java" de Josh Bloch pour plus de détails.

1
markusk

Singleton va bien, selon le contexte.

À des fins de test, vous voudrez peut-être simuler des références à des singletons pour éviter les effets secondaires lors des tests unitaires. Dans ce cas, il est probablement judicieux d'utiliser un framework d'injection de dépendances tel que Spring pour gérer la création de l'instance et d'utiliser des méthodes régulières qui peuvent être remplacées par des méthodes statiques.

Si vous envisagez toujours d'utiliser des méthodes statiques, assurez-vous que les appels sont thread-safe s'ils sont utilisés dans un contexte multi-thread. (par exemple, double vérification du verrouillage).

1
Jin Kim