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, je l'utilise 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 bouge 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, serait-ce donc 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 formidables!
Réponses:
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 uneRandom
instance, 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 donc il n'y a 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 c'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 en 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. En Java, il existe des moyens 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 programmeur typique supposera d'emblée qu'il s'agit d'une fonction pure. Dévier du comportement attendu est la façon dont vous avez tendance à créer des bogues dans votre programme, en général et à éviter.
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:
la source
Dice.roll()
n'est pas une exception valable à la règle «pas d'état global».random.nextInt(6) + 1
. ;)RollAndMove()
nouveau si nous fournissons un double six, la façon la plus simple et la plus robuste de le faire est de simuler l'unDice
ou l' autre ou le générateur de nombres aléatoires. Ergo,Dice
ne veut pas être une classe statique utilisant un générateur aléatoire statique.Pour donner un exemple des limites d'une
static
classe, 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" afin qu'ils ne puissent jamais "tâtonner" (lancer 1).
Dice.roll(bonus, sides, isFumbleAllowed)
.Cela devient désordonné, n'est-ce pas?
la source
new Dice().roll(...)
doit être concidered accès statique ainsi queDice.roll(...)
. Nous ne bénéficions que si nous injectons cette dépendance.static
désordre se produit dans chaque appel, et les connaissances nécessaires sont requises dans chaque appel, donc il est éclaboussé partout dans votre application. Dans une structure POO, seul le constructeur / l'usine doit être désordonné et les détails de ce dé sont encapsulés. Après cela, utilisez le polymorphisme et appelez simplementroll()
. Je pourrais modifier cette réponse pour clarifier.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 Dice entièrement statique. Voir /programming/4482315/why-does-mockito-not-mock-static-methods
la source
Ceci est en fait connu comme le modèle Monostate , où chaque instance (et même une "non-instance") partage son statut. Chaque membre est un membre de la 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
c'est certainement plus clair et sémantiquement meilleur (il est partagé entre la classe elle-même et toutes ses instances) questatic
(reste après le cycle de vie de l'étendue dans laquelle il est déclaré).la source