Différence entre java enum sans valeur et classe d’utilitaire avec constructeur privé

Une chose courante à faire aux classes d’utilitaires est de leur donner un constructeur privé :

public final class UtilClass { private UtilClass() {} ... } 

Mais malheureusement, certains outils n’aiment pas ce constructeur privé. Ils peuvent avertir qu’il n’est jamais appelé dans la classe, qu’il n’est pas couvert par les tests, que le bloc ne contient pas de commentaire, etc.

Beaucoup de ces avertissements disparaissent si vous le faites à la place:

 public enum UtilClass {; ... } 

Ma question est la suivante: outre la haine sans fin des futurs développeurs, quelles sont les principales différences entre une énumération sans valeur et une classe avec un constructeur privé en Java?

Notez que je ne demande pas quel est l’avantage d’une énumération Java par rapport à une classe avec des champs finaux statiques publics? . Je ne décide pas si une liste d’éléments doit être un groupe de constantes ou une énumération, je décide de placer un groupe de fonctions dans une classe sans constructeur ou une énumération sans valeur.

Notez également que je ne veux pas réellement faire cela. Je veux juste connaître les compromis dans le cadre des connaissances linguistiques générales.

Par exemple, l’utilisation d’une énumération pollue l’ UtilClass.values() avec des méthodes inutiles telles que UtilClass.values() . Quels sont les autres inconvénients? Upsides?

L’un des avantages est que vous êtes absolument assuré qu’aucune instance ne peut être créée, même à l’intérieur de la classe.

Un inconvénient est que cela va au-delà de l’intention habituelle des enums. Cependant, nous le faisons déjà pour les singletons implémentés avec des enums.

Ce bit de “Effective Java” de Joshua Bloch à propos de ces singletons s’applique également aux classes d’utilitaires:

… vous obtenez une garantie absolue qu’il ne peut y avoir d’instance autre que les constantes déclarées. La JVM offre cette garantie et vous pouvez vous en fier.

Clause de non-responsabilité: Je n’ai pas utilisé ce modèle et ne recommande ni pour ni contre.

Utiliser enum pour quelque chose qui n’est pas réellement une enum est vilain et déroutant. Je dirais que c’est une raison suffisante pour ne pas le faire.

Le modèle de “classe d’utilité” est parfaitement légitime. Si vos outils ne vous plaisent pas, c’est un problème avec les outils.

Le modèle suivant dans les classes d’utilité fournit également une garantie absolue qu’il ne peut y avoir d’instance:

 public abstract class Util { private Util() { throw new Error(); } ... // static methods } 

En outre, vous n’avez aucune autre méthode statique non pertinente, fournie par les énumérations.

La seule différence est que vous pouvez toujours appeler le constructeur dans votre classe :

 public final class UtilityClass { public static final UtilityClass Instance = new UtilityClass(); private UtilityClass () {} public static int Foo (int a, int b) { return a+b; } } 

Mais puisque vous êtes le concepteur de cette classe, cela n’aurait aucun sens de rompre vos propres contrats de code.

En général, la plupart des manuels de conception de logiciels que j’ai jamais lus sont contre l’utilisation de méthodes statiques . À moins qu’il ne s’agisse vraiment de méthodes utilitaires: dans le sens où elles ne nécessiteront jamais aucun état. Et même dans ce cas, il ne s’agit que d’un petit effort pour implémenter un motif Singleton tel que, le moment venu, vous pouvez lui affecter un état:

 public final class UtilityClass { public static final UtilityClass Instance = new UtilityClass(); private UtilityClass () {} public int Foo (int a, int b) { return a+b; } } 

Et l’appelez avec UtilityClass.Instance.Foo(2,5); . Il serait beaucoup plus difficile d’effectuer une transformation d’ état par la suite dans le processus de codage. Ainsi, les méthodes statiques sont plus difficiles à maintenir.

La raison pour laquelle les instances sont utiles est que vous pouvez les utiliser dans de nombreux modèles, tels que Strategy, si cela dépend parfois de ce qui doit être fait, … En utilisant static méthodes static , on rend les méthodes moins dynamics car Java ne le permet pas. t support des pointeurs de méthodes (pour de bonnes raisons). Ainsi, les méthodes non statiques sont plus dynamics et utiles.

En outre, certains chercheurs en sécurité affirment qu’il est plus difficile d’parsingr le code avec static modificateurs static car ils sont accessibles de partout et les effets secondaires sont moins prévisibles (par exemple, dans un outil d’parsing automatique de la sécurité): par exemple, vous avez une classe qui n’est pas complètement implémentée. Ensuite, vous pouvez toujours parsingr les champs pour savoir à quelles méthodes il peut avoir access et parsingr ainsi les éventuels effets secondaires (utilisation du réseau, fichier IO, …). Cela peut générer une liste de dangers possibles par classe à vérifier. Du moins si j’ai bien compris la thèse de doctorat de l’un de mes collègues chercheurs. Ainsi, les méthodes non statiques permettent une parsing plus poussée des modificateurs.

Pour conclure: Java a été construit sur le principe de la programmation orientée object. Cela signifie que le “monde de la classe” est utilisé par le compilateur et le “monde de la matière” par le interpréteur / le temps d’exécution. Je conviens qu’il y a beaucoup de conflits entre les deux mots. Mais static méthodes static sont dans de nombreux cas / une erreur pour résoudre de tels conflits.