J'ai une classe pleine de fonctions utilitaires. Instancier une instance de celui-ci n'a aucun sens sémantique, mais je veux toujours appeler ses méthodes. Quelle est la meilleure façon de gérer cela? Classe statique? Abstrait?
J'ai une classe pleine de fonctions utilitaires. Instancier une instance de celui-ci n'a aucun sens sémantique, mais je veux toujours appeler ses méthodes. Quelle est la meilleure façon de gérer cela? Classe statique? Abstrait?
Réponses:
Constructeur privé et méthodes statiques sur une classe marquée comme finale.
D'après le grand livre "Effective Java" :
Point 4: Appliquer la non-instabilité avec un constructeur privé
- Tenter d'imposer la non-instabilité en créant une classe abstraite ne fonctionne pas.
- Un constructeur par défaut n'est généré que si une classe ne contient aucun constructeur explicite, donc une classe peut être rendue non instanciable en incluant un constructeur privé:
// Noninstantiable utility class
public class UtilityClass
{
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
}
Étant donné que le constructeur explicite est privé, il est inaccessible en dehors de la classe. AssertionError n'est pas strictement obligatoire, mais il fournit une assurance au cas où le constructeur serait accidentellement appelé à partir de la classe. Il garantit que la classe ne sera jamais instanciée en aucune circonstance. Cet idiome est légèrement contre-intuitif, car le constructeur est fourni expressément afin qu'il ne puisse pas être invoqué. Il est donc judicieux d'inclure un commentaire, comme indiqué ci-dessus.
En tant qu'effet secondaire, cet idiome empêche également la classe d'être sous-classée. Tous les constructeurs doivent appeler un constructeur de superclasse, explicitement ou implicitement, et une sous-classe n'aurait aucun constructeur de superclasse accessible à invoquer.
AssertionError
sur d' autres alternatives comme IllegalStateException
, UnsupportedOperationException
, etc?
On dirait que vous avez une classe utilitaire similaire à java.lang.Math .
L'approche est la classe finale avec un constructeur privé et des méthodes statiques.
Mais méfiez-vous de ce que cela fait pour la testabilité, je recommande de lire cet article
Les méthodes statiques sont mortes pour la testabilité
Juste pour nager en amont, les membres statiques et les classes ne participent pas à l'OO et sont donc diaboliques. Non, pas mal, mais sérieusement, je recommanderais une classe régulière avec un modèle singleton pour l'accès. De cette façon, si vous avez besoin de remplacer le comportement dans tous les cas sur la route, ce n'est pas un réoutillage majeur. OO est votre ami :-)
Mon 0,02 $
commentez les arguments du "constructeur privé": allez, les développeurs ne sont pas si stupides; mais ils SONT paresseux. créer un objet puis appeler des méthodes statiques? ça n'arrivera pas.
ne passez pas trop de temps à vous assurer que votre classe ne peut pas être mal utilisée. ayez confiance en vos collègues. et il existe toujours un moyen d'abuser de votre classe, quelle que soit la manière dont vous la protégez. la seule chose qui ne peut pas être mal utilisée est une chose qui est complètement inutile.
Il ne sert à rien de déclarer la classe comme static
. Déclarez simplement ses méthodes static
et appelez-les à partir du nom de la classe comme d'habitude, comme la classe Math de Java .
De plus, même s'il n'est pas strictement nécessaire de rendre le constructeur privé, c'est une bonne idée de le faire. Marquer le constructeur comme privé empêche d'autres personnes de créer des instances de votre classe, puis d'appeler des méthodes statiques à partir de ces instances. (Ces appels fonctionnent exactement de la même manière en Java, ils sont juste trompeurs et nuisent à la lisibilité de votre code.)
Vous pouvez utiliser l'annotation @UtilityClass de lombok https://projectlombok.org/features/experimental/UtilityClass