Pourquoi et quand devrais-je faire une classe 'statique'? Quel est le but du mot clé 'statique' sur les classes?

47

Le staticmot-clé sur un membre dans de nombreuses langues signifie que vous ne devriez pas créer une instance de cette classe pour pouvoir accéder à ce membre. Cependant, je ne vois aucune justification pour faire une classe entière static. Pourquoi et quand devrais-je faire un cours static?

Quels sont les avantages de faire un cours static? Je veux dire, après avoir déclaré une classe statique, il faut quand même déclarer tous les membres auxquels il / elle veut avoir accès sans instanciation, comme statiques également.

Cela signifie que, par exemple, la Mathclasse pourrait être déclarée normale (non statique), sans affecter le code utilisé par les développeurs. En d'autres termes, rendre une classe statique ou normale est en quelque sorte transparent pour les développeurs.

Saeed Neamati
la source
Si vous codez dans le style Func Prog à la manière de Rich Hickey, cela peut être utile.
Job
1
À mon avis, les classes statiques ne sont qu'une béquille par laquelle C # tente de masquer un défaut de conception massif dans le langage. Pourquoi structurer une langue autour de cette idéologie absurde qui veut que la classe soit une classe, pour ensuite introduire une syntaxe supplémentaire afin que vous puissiez tricher et contourner cette restriction inutile. Si C # venait juste d'autoriser les fonctions libres dès le départ, les classes statiques ne seraient plus nécessaires.
Antred

Réponses:

32

Cela montre clairement aux utilisateurs comment la classe est utilisée. Par exemple, écrire le code suivant serait insensé:

Math m = new Math();

C # ne pas avoir à interdire cela , mais puisqu'il ne sert à rien, pourrait aussi bien indiquer à l'utilisateur. Certaines personnes (y compris moi) adhèrent à la philosophie selon laquelle les langages de programmation (et les API…) doivent être aussi restrictifs que possible pour les rendre difficiles à utiliser de manière erronée: les seules opérations autorisées sont alors celles qui ont un sens et (espérons-le) correctes.

Konrad Rudolph
la source
3
Je ne suis pas d'accord avec cette philosophie. Le problème que j'ai est qu'il faut changer. Ainsi, bien qu’il ait pu sembler logique de la limiter avant maintenant, cette restriction empêche notre développement de répondre aux besoins futurs. Et la bibliothèque héritée que nous sommes obligés d’utiliser pour l’interface avec l’ancien système (celle que vous avez écrite et scellée et statuée sur toutes les classes) ne nous fournit aucun moyen d’étendre ou de modifier le code que vous avez écrit. Le fait que vous n’ayez aucune raison d’instancier votre classe ne signifie pas que je n’en aurai plus besoin. Bien que statifier une classe d’utilité ait du sens, songez également à l’avenir.
SoylentGray
19
@Chad Ensuite, la bibliothèque est mal conçue. L'extension des classes qui n'étaient pas conçues pour l'extension ne fonctionne finalement pas, il est donc préférable de créer la classe sealeden premier lieu. Je reconnais que tout le monde n'est pas d'accord avec ce sentiment, mais les commentaires ne sont pas un bon endroit pour en discuter. Mais dans le cas de staticce problème ne se pose même pas: l'instanciation System.Mathn'aura jamais de sens.
Konrad Rudolph
1
@Konard, si vous déclarez tous les membres de la Mathclasse comme statiques sans déclarer la Mathclasse comme statiques, vous pouvez néanmoins l'utiliser, sans avoir besoin d'instanciation.
Saeed Neamati
11
@Saeed - C'est vrai, mais vous pouvez aussi instancier la classe, ce qui ne sert à rien. Que dois-je faire avec une instance de la classe Math? Pour montrer explicitement l'intention de la classe (pas d'instanciation nécessaire ou souhaitée), c'est marqué static.
Corbin Mars
3
@ Saeed Retournons ceci: je vous propose de relire ma réponse car vous semblez l'avoir mal comprise: vos commentaires ne sont pas liés à ma réponse. Je n'ai jamais dit qu'il fallait écrire new Math().
Konrad Rudolph
24

StackOverflow a une excellente discussion sur ce sujet . Pour plus de commodité, je vais le copier-coller ici, au nom de son auteur, Mark S. Rasmussen :

J'ai écrit mes pensées sur les classes statiques dans un fil précédent :

J'aimais les classes utilitaires remplies de méthodes statiques. Ils ont procédé à une excellente consolidation des méthodes d'assistance qui, autrement, auraient été générées, entraînant redondance et maintenance. Ils sont très faciles à utiliser, aucune instanciation, aucune élimination, rien que du feu. J'imagine que c'était ma première tentative involontaire de créer une architecture orientée service - de nombreux services sans état qui faisaient simplement leur travail et rien d'autre. Cependant, à mesure que le système se développe, les dragons arrivent.

Polymorphisme

Disons que nous avons la méthode UtilityClass.SomeMethod qui bourdonne joyeusement. Tout à coup, nous devons modifier légèrement les fonctionnalités. La plupart des fonctionnalités sont les mêmes, mais nous devons néanmoins modifier quelques éléments. Si cela n’avait pas été une méthode statique, nous pourrions créer une classe de dérivés et modifier le contenu de la méthode selon les besoins. Comme c'est une méthode statique, nous ne pouvons pas. Bien sûr, si nous devons simplement ajouter des fonctionnalités avant ou après l’ancienne méthode, nous pouvons créer une nouvelle classe et appeler l’ancienne à l’intérieur de celle-ci - mais c’est tout simplement dégoûtant.

Malheurs d'interface

Les méthodes statiques ne peuvent pas être définies via des interfaces pour des raisons logiques. Et comme nous ne pouvons pas redéfinir les méthodes statiques, les classes statiques sont inutiles lorsque nous devons les transmettre par leur interface. Cela nous rend incapables d'utiliser des classes statiques dans le cadre d'un modèle de stratégie. Nous pourrions corriger certains problèmes en passant des délégués à la place des interfaces.

Essai

Cela va fondamentalement de pair avec les problèmes d’interface mentionnés ci-dessus. Notre capacité d'interchanger les implémentations étant très limitée, nous aurons également du mal à remplacer le code de production par le code de test. Encore une fois, nous pouvons les envelopper mais cela nous demandera de modifier de grandes parties de notre code simplement pour pouvoir accepter des wrappers à la place des objets réels.

Favorise les blobs

Comme les méthodes statiques sont généralement utilisées en tant qu'utilitaires et que leurs méthodes ont des objectifs différents, nous allons rapidement nous retrouver avec une classe volumineuse remplie de fonctionnalités non cohérentes. Idéalement, chaque classe doit avoir un objectif unique au sein du système. Je préférerais de beaucoup avoir cinq fois les classes tant que leurs objectifs sont bien définis.

Paramètre fluage

Pour commencer, cette petite méthode statique mignonne et innocente peut prendre un seul paramètre. À mesure que la fonctionnalité augmente, deux nouveaux paramètres sont ajoutés. Bientôt d'autres paramètres, facultatifs, sont ajoutés. Nous créons donc des surcharges de la méthode (ou ajoutons simplement des valeurs par défaut, dans les langues qui les prennent en charge). D'ici peu, nous avons une méthode qui prend 10 paramètres. Seuls les trois premiers sont vraiment nécessaires, les paramètres 4 à 7 sont facultatifs. Mais si le paramètre 6 est spécifié, vous devez également renseigner 7-9 ... Si nous avions créé une classe dans le seul but de faire ce que cette méthode statique a fait, nous pourrions résoudre ce problème en prenant les paramètres requis dans le fichier. constructeur, et en permettant à l'utilisateur de définir des valeurs facultatives via des propriétés ou des méthodes permettant de définir plusieurs valeurs interdépendantes en même temps. Aussi,

Demander aux consommateurs de créer une instance de classes sans raison

Un des arguments les plus courants est, pourquoi demander aux consommateurs de notre classe de créer une instance pour invoquer cette méthode unique, sans utiliser l’instance par la suite? Créer une instance d'une classe est une opération très très économique dans la plupart des langues, la rapidité n'est donc pas un problème. L'ajout d'une ligne de code supplémentaire au consommateur représente un faible coût pour poser les bases d'une solution beaucoup plus facile à gérer dans le futur. Enfin, si vous souhaitez éviter de créer des instances, créez simplement un wrapper singleton de votre classe qui permette une réutilisation facile - bien que cela rende l'exigence que votre classe soit sans état. Si ce n'est pas sans état, vous pouvez toujours créer des méthodes de wrapper statiques qui gèrent tout, tout en vous offrant tous les avantages à long terme. Finalement,

Seul un Sith traite en absolus

Bien sûr, il y a des exceptions à mon aversion pour les méthodes statiques. Les vraies classes d'utilitaires qui ne posent aucun risque de gonflement constituent d'excellents cas pour les méthodes statiques - System.Convert par exemple. Si votre projet est unique et ne nécessite aucune maintenance future, l'architecture globale n'est pas très importante - statique ou non statique, peu importe - la vitesse de développement l'est toutefois.

Normes, normes, normes!

L'utilisation de méthodes d'instance ne vous empêche pas d'utiliser également des méthodes statiques, et inversement. Tant que la différenciation est raisonnée et normalisée. Il n'y a rien de pire que de regarder une couche métier contenant différentes méthodes d'implémentation.

Meule
la source
12
Hmmm, je ne sais pas si je copierais et collerais une réponse complète ici. Peut-être que lier et paraphraser, inclure un point de vue alternatif puisque vous parlez d'une "discussion", partager votre propre expérience?
Corbin Mars
2
"Seul un Sith fait des affaires en absolu" - Je n'avais jamais vu cela utiliser comme ça avant ... mais c'est PARFAIT. M'a fait lol.
Brook
4
@Corbin: Mark a eu une excellente réponse. Je lui ai donné crédit et j'ai copié / collé pour plus de facilité. Mon point de vue sur le sujet correspond à celui de Mark. Je ne vois pas l'intérêt de votre commentaire, si ce n'est de commencer le débat.
Rick
1
@Rick: La réponse copiée est assez longue, et la paraphraser serait certainement utile. Une phrase du genre "Ce n’est pas simplement qu’ils ne sont pas vraiment utiles, ils peuvent même nuire, comme le montre ce post SO:" me permettrait de le sauter rapidement, car je vois que ce n’est pas l’information que je cherchais.
Blubb
@Simon: LOL I 1 + 'ed votre post. Pour tenter d'arrêter de discuter pour quelque chose d'aussi stupide, je suis simplement d'accord. :) J'espère que l'affiche originale a trouvé ma réponse / copier / coller utile.
Rick
16

Je suis surpris que personne d'autre n'ait mentionné que les staticclasses autorisent les méthodes d'extension - étendre en toute sécurité un type existant (y compris l' ajout de définitions de méthodes aux interfaces ) que vous ne possédez pas. Par exemple, qu’est-ce qu’en Scala

trait MyFoo {
  def foo: Int
  def plusFoo(a: Int) = foo + a
}

peut être exprimé en C # comme

public interface IMyFoo {
  int Foo();
}

public static class MyFooExtensions {
  public static int PlusFoo(this IMyFoo f, int a) {
    return f.Foo() + a;
  }
}
Frank Shearar
la source
vous avez trouvé une aiguille dans la botte de foin. +1
Saeed Neamati
3

Pour moi, une classe statique (en C #) est un peu comme appeler une fonction.

Par exemple

public static string DoSomething(string DoSomethingWithThisString){}

Je passe une chaîne et récupère une chaîne. Tout est contenu dans cette méthode. Pas d'accès à la variable membre, etc.

Honnêtement, son utilisation a principalement consisté à réduire les lignes de code:

Pourquoi faire:

MyClass class = new MyClass();
String s = class.DoSomething("test");

Quand je peux faire ça:

String s = MyClass.DoSomething("test");

Donc, j'utilisais des classes statiques dans ces cas-là, quand je voulais faire quelque chose sans avoir besoin d'une classe et que cela voulait dire moins de dactylographie.

Les points de Mark S. sont valables, mais pour moi, si j'ai des méthodes utilitaires, il est simplement plus facile de prétendre que j'appelle une fonction pour les référencer en tant que doublures.

C'est peut-être simpliste, mais c'est principalement comme ça que j'ai utilisé static.

Jon Raynor
la source
1
new MyClass (). DoQuelque chose ("test") est toujours valide. J'utilise beaucoup cela pour les constructeurs de données de test.
JoanComasFdz