Java: classe statique?

130

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?

Nick Heiner
la source
14
Au fait, vous ne pouvez pas rendre statique une classe de haut niveau ...
Jon

Réponses:

163

Constructeur privé et méthodes statiques sur une classe marquée comme finale.

David Robles
la source
19
@matt b: Comme le souligne David Robles dans sa réponse, vous n'avez pas besoin de rendre la classe finale ... elle ne peut pas être sous-classée car une sous-classe ne pourra pas invoquer un constructeur de super classe car il est privé. Cependant ... pas de mal à être explicite. Mais jfyi :-).
Tom
93

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.

David Robles
la source
1
Pourquoi avez - vous choisi AssertionErrorsur d' autres alternatives comme IllegalStateException, UnsupportedOperationException, etc?
Pacerier
@Pacerier Voir ça .
bcsb1001
@ bcsb1001, cela nous amène à ceci .
Pacerier
21

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é

Crowne
la source
Alors java.lang.Math est-il "mort à la testabilité"?
Pacerier
1
Il pourrait être intéressant de voir comment il obtient un score lorsqu'il est exécuté via code.google.com/p/testability-explorer
Crowne
6

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 $

Bennett Dill
la source
17
Les singletons sont également considérés comme mauvais.
Dan Dyer
3
Vous utilisez le constructeur privé pour empêcher quiconque d'instancier ou de sous-classer la classe. Voir la réponse de David Robles: stackoverflow.com/questions/1844355/java-static-class/...
rob
5
singleton n'est pas plus mauvais que l'injection de dépendances :)
irréputable
12
OO a sa place, mais il y a des moments où ce n'est tout simplement pas pratique, ou ce serait un gaspillage de ressources - par exemple, quelque chose d'aussi simple que Math.abs (). Il n'y a aucune raison d'instancier un objet juste pour instancier un objet, alors qu'un appel de méthode statique vous aurait tout aussi bien servi sans aucune surcharge OO. ;)
rob
2
@rob re OO, je suis d'accord, Math.Abs ​​n'a probablement jamais besoin d'une instance. Quand j'entends "j'ai une classe utilitaire", je vois Math.Avg (), où vous devez maintenant ajouter pris en charge pour une moyenne pondérée. Je vois un générateur d'URL, param in, url out qui doit être refactorisé pour prendre en charge href, ou url uniquement, etc. Aussi, maintenant je vais abandonner la tactique défensive OO standard, les tests! / me ducks
Bennett Dill
3

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.

irréprochable
la source
7
Quelqu'un qui a vu (dans le code de production, pas dans le code étudiant jsut) object.staticMethod Je pense que vous surestimez les capacités de Joe Random Programmer! :-P
TofuBeer
2
  • Classe finale et constructeur privé (bon mais pas indispensable)
  • Méthodes statiques publiques
fastcodejava
la source
1

Il ne sert à rien de déclarer la classe comme static. Déclarez simplement ses méthodes staticet 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.)

Bill le lézard
la source
1
N'oubliez pas non plus de créer un constructeur privé.
Asaph
@Asaph: D'accord. J'ai ajouté un peu à ma réponse. Merci.
Bill the Lizard
Si vous voulez des méthodes statiques dans une classe interne, la classe doit également être statique.
Rui Marques