web-dev-qa-db-fra.com

Java - Est-ce une mauvaise idée d'avoir des classes entièrement statiques?

Je travaille sur un projet solo plus important et en ce moment, et j'ai plusieurs classes dans lesquelles je ne vois aucune raison de créer une instance de.

Ma classe de dés en ce moment, par exemple, stocke toutes ses données statiquement et toutes ses méthodes sont également statiques. Je n'ai pas besoin de l'initialiser car lorsque je veux lancer les dés et obtenir une nouvelle valeur, j'utilise simplement Dice.roll().

J'ai plusieurs classes similaires qui n'ont qu'une seule fonction principale comme celle-ci et je suis sur le point de commencer à travailler sur une sorte de classe "contrôleur" qui sera en charge de tous les événements (comme quand un joueur se déplace et quel tour en cours) il est) et j'ai trouvé que je pouvais suivre la même idée pour cette classe. Je ne prévois jamais de créer plusieurs objets pour ces classes spécifiques, donc serait-ce une mauvaise idée de les rendre entièrement statiques?

Je me demandais si cela était considéré comme une "mauvaise pratique" en ce qui concerne Java. D'après ce que j'ai vu, la communauté semble être un peu divisée sur ce sujet? Quoi qu'il en soit, j'adorerais en discuter et les liens vers les ressources seraient également très bien!

16
HexTeke

Il n'y a rien de mal avec les classes statiques qui sont vraiment statiques. C'est-à-dire qu'il n'y a pas d'état interne à proprement parler qui ferait évoluer la sortie des méthodes.

Si Dice.roll() renvoie simplement un nouveau nombre aléatoire de 1 à 6, il ne change pas d'état. Certes, vous partagez peut-être une instance de Random, mais je ne considérerais pas qu'un changement d'état comme par définition, la sortie sera toujours bien, aléatoire. Il est également thread-safe, il n'y a donc aucun problème ici.

Vous verrez souvent des "Helper" finales ou d'autres classes utilitaires qui ont un constructeur privé et des membres statiques. Le constructeur privé ne contient aucune logique et sert uniquement à empêcher quelqu'un d'instancier la classe. Le dernier modificateur ramène cette idée à la maison que ce n'est pas une classe dont vous voudriez jamais dériver. Il s'agit simplement d'une classe d'utilité. Si cela est fait correctement, il ne devrait pas y avoir de singleton ou d'autres membres de classe qui ne soient pas eux-mêmes statiques et définitifs.

Tant que vous suivez ces directives et que vous ne faites pas de singletons, il n'y a absolument rien de mal à cela. Vous mentionnez une classe de contrôleur, et cela nécessitera presque certainement des changements d'état, donc je déconseille d'utiliser uniquement des méthodes statiques. Vous pouvez vous appuyer fortement sur une classe d'utilité statique, mais vous ne pouvez pas faire une classe d'utilité statique.


Qu'est-ce qui est considéré comme un changement d'état pour une classe? Eh bien, permet d'exclure des nombres aléatoires pendant une seconde, car ils ne sont pas déterministes par définition et donc la valeur de retour change souvent.

Une fonction pure est une fonction déterministe, c'est-à-dire que pour une entrée donnée, vous obtiendrez une et exactement une sortie. Vous voulez que les méthodes statiques soient de pures fonctions. Dans Java il y a des façons de modifier le comportement des méthodes statiques pour conserver l'état, mais ce ne sont presque jamais de bonnes idées. Lorsque vous déclarez une méthode comme statique, le type le programmeur supposera dès le départ qu'il s'agit d'une fonction pure. Déviant du comportement attendu est la façon dont vous avez tendance à créer des bogues dans votre programme, d'une manière générale et devrait être évité.

Un singleton est une classe contenant des méthodes statiques aussi opposées que possible à la "fonction pure". Un seul membre privé statique est conservé en interne à la classe qui est utilisée pour garantir qu'il y a exactement une instance. Ce n'est pas la meilleure pratique et peut vous causer des ennuis plus tard pour un certain nombre de raisons. Pour savoir de quoi nous parlons, voici un exemple simple de singleton:

// DON'T DO THIS!
class Singleton {
  private String name; 
  private static Singleton instance = null;

  private Singleton(String name) {
    this.name = name;
  }

  public static Singleton getInstance() {
    if(instance == null) {
      instance = new Singleton("George");
    }
    return instance;
  }

  public getName() {
    return name;
  }
}

assert Singleton.getInstance().getName() == "George"
21
Neil

Pour donner un exemple des limitations d'une classe static, que se passe-t-il si certains de vos joueurs souhaitent obtenir un léger bonus sur leurs jets de dé? Et ils sont prêts à payer beaucoup d'argent! :-)

Oui, vous pouvez ajouter un autre paramètre, donc Dice.roll(bonus),

Plus tard, vous aurez besoin de D20.

Dice.roll(bonus, sides)

Oui, mais certains joueurs ont l'exploit "suprêmement capable" de sorte qu'ils ne peuvent jamais "tâtonner" (lancer 1).

Dice.roll(bonus, sides, isFumbleAllowed).

Cela devient désordonné, n'est-ce pas?

10
user949300

Dans le cas particulier d'une classe Dice, je pense que l'utilisation de méthodes d'instance plutôt que de statistiques rendra les tests beaucoup plus faciles.

Si vous voulez tester un élément quelque chose qui utilise une instance de dés (par exemple une classe de jeu), à partir de vos tests, vous pouvez injecter une forme de test double de dés qui renvoie toujours une séquence fixe de valeurs. Votre test peut vérifier que le jeu a le bon résultat pour ces lancers de dés.

Je ne suis pas un développeur Java mais je pense qu'il serait beaucoup plus difficile de le faire avec une classe de dés entièrement statique. Voir https://stackoverflow.com/questions/4482315/pourquoi-ne-mockito-pas-mock-méthodes-statiques

3
bdsl

Ceci est en fait connu sous le nom de modèle Monostate , où chaque instance (et même une "non-instance") partage son statut. Chaque membre est un membre de classe (c'est-à-dire aucun membre d'instance). Ils sont couramment utilisés pour implémenter des classes "toolkit" qui regroupent un ensemble de méthodes et de constantes liées à une seule responsabilité ou exigence mais n'ont pas besoin d'un état pour fonctionner (elles sont purement fonctionnelles). En fait, Java est fourni avec certains d'entre eux (par exemple, Math ).

Un peu hors sujet: je suis rarement d'accord avec la dénomination des mots-clés dans VisualBasic, mais dans ce cas, je pense que shared est certainement plus clair et sémantiquement meilleur (c'est partagé parmi la classe elle-même et toutes ses instances) que static (reste après le cycle de vie de la portée dans laquelle il est déclaré).

0
Jesus Alonso Abad