web-dev-qa-db-fra.com

Pourquoi et quand devrais-je rendre une classe «statique»? À quoi sert le mot-clé «statique» sur les classes?

Le mot clé static sur un membre dans de nombreuses langues signifie que vous ne devez pas créer d'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 dois-je créer une classe static?

Quels avantages puis-je tirer de la création d'une classe static? Je veux dire, après avoir déclaré une classe statique, il faut toujours déclarer tous les membres auxquels il veut avoir accès sans instanciation, comme statiques aussi.

Cela signifie que, par exemple, la classe Math peut être déclarée normale (pas statique), sans affecter la façon dont les développeurs codent. En d'autres termes, rendre une classe statique ou normale est un peu transparent pour les développeurs.

48
Saeed Neamati

Il montre clairement aux utilisateurs comment la classe est utilisée. Par exemple, il serait complètement insensé d'écrire le code suivant:

Math m = new Math();

C # ne doit interdire cela, mais comme il ne sert à rien, il pourrait tout aussi bien le dire à l'utilisateur. Certaines personnes (dont moi) adhèrent à la philosophie selon laquelle les langages de programmation (et les API…) devraient être aussi restrictifs que possible pour les rendre difficiles à utiliser de manière incorrecte: les seules opérations autorisées sont alors celles qui sont significatives et (espérons-le) correctes.

34
Konrad Rudolph

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

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

J'aimais les classes utilitaires remplies de méthodes statiques. Ils ont fait une grande consolidation des méthodes d'assistance qui autrement résideraient, causant la redondance et l'enfer de la maintenance. Ils sont très faciles à utiliser, pas d'instanciation, pas d'élimination, juste fire'n'forget. Je suppose que c'était ma première tentative involontaire de créer une architecture orientée services - beaucoup de services apatrides qui ont fait leur travail et rien d'autre. Cependant, à mesure qu'un système se développe, des dragons arrivent.

Polymorphisme

Disons que nous avons la méthode UtilityClass.SomeMethod qui bourdonne joyeusement. Du coup, nous devons légèrement changer la fonctionnalité. La plupart des fonctionnalités sont les mêmes, mais nous devons néanmoins modifier quelques éléments. S'il ne s'agissait pas d'une méthode statique, nous pourrions créer une classe dérivée 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 avons juste besoin d'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 juste grossier.

Problèmes 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 remplacer les méthodes statiques, les classes statiques sont inutiles lorsque nous devons les passer par leur interface. Cela nous rend incapables d'utiliser des classes statiques dans le cadre d'un modèle de stratégie. Nous pouvons corriger certains problèmes en passant des délégués au lieu d'interfaces.

Test

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

Favorise les blobs

Comme les méthodes statiques sont généralement utilisées comme méthodes utilitaires et que les méthodes utilitaires ont généralement des objectifs différents, nous nous retrouverons rapidement avec une grande classe remplie de fonctionnalités non cohérentes - idéalement, chaque classe devrait avoir un seul objectif dans le système. Je préférerais de beaucoup avoir cinq fois les cours tant que leurs objectifs sont bien définis.

Fluage des paramètres

Pour commencer, cette petite méthode statique mignonne et innocente pourrait prendre un seul paramètre. À mesure que la fonctionnalité grandit, quelques nouveaux paramètres sont ajoutés. Bientôt, d'autres paramètres sont ajoutés qui sont facultatifs, 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). Avant longtemps, nous avons une méthode qui prend 10 paramètres. Seuls les trois premiers sont vraiment requis, les paramètres 4-7 sont facultatifs. Mais si le paramètre 6 est spécifié, 7-9 doivent également être remplis ... 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 constructeur, et permettant à l'utilisateur de définir des valeurs facultatives via des propriétés ou des méthodes pour définir plusieurs valeurs interdépendantes en même temps. De plus, si une méthode a atteint cette complexité, elle doit de toute façon être dans sa propre classe.

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

L'un des arguments les plus courants est la suivante: pourquoi exiger que les consommateurs de notre classe créent une instance pour invoquer cette méthode unique, tout en n'ayant aucune utilisation de l'instance par la suite? La création d'une instance d'une classe est une opération très très bon marché dans la plupart des langues, donc la vitesse n'est pas un problème. L'ajout d'une ligne de code supplémentaire au consommateur est un faible coût pour jeter les bases d'une solution beaucoup plus maintenable à l'avenir. Et enfin, si vous voulez éviter de créer des instances, créez simplement un wrapper singleton de votre classe qui permet une réutilisation facile - bien que cela oblige votre classe à être sans état. S'il n'est pas sans état, vous pouvez toujours créer des méthodes d'encapsuleur statiques qui gèrent tout, tout en vous offrant tous les avantages à long terme. Enfin, vous pouvez également créer une classe qui masque l'instanciation comme s'il s'agissait d'un singleton: MyWrapper.Instance est une propriété qui renvoie simplement new MyClass ();

Seul un Sith traite en absolu

Bien sûr, il y a des exceptions à mon aversion pour les méthodes statiques. Les véritables classes d'utilité qui ne présentent aucun risque de ballonnement sont d'excellents cas pour les méthodes statiques - System.Convert comme exemple. Si votre projet est ponctuel sans aucune exigence de maintenance future, l'architecture globale n'est vraiment pas très importante - statique ou non statique, peu importe - la vitesse de développement, cependant.

Normes, normes, normes!

L'utilisation de méthodes d'instance ne vous empêche pas d'utiliser également des méthodes statiques, et vice versa. Tant qu'il y a un raisonnement derrière la différenciation et qu'elle est standardisée. Il n'y a rien de pire que de regarder par-dessus une couche métier étendue avec différentes méthodes de mise en œuvre.

25
Rick

Je suis surpris que personne d'autre n'ait mentionné que les classes static permettent méthodes d'extension - étendant en toute sécurité un type existant (y compris ajoutant des définitions de méthode aux interfaces ) que vous ne possédez pas. Par exemple, ce qui dans Scala est

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;
  }
}
16
Frank Shearar

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, la plupart du temps, mon utilisation a été de réduire les lignes de code:

Pourquoi faire:

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

Quand je peux le faire:

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

Donc, j'utilisais des classes statiques dans ces cas, quand je voulais faire quelque chose sans avoir besoin d'une classe et que cela signifierait moins de frappe.

Les points Mark S. sont valides, mais pour moi, si j'ai des méthodes utilitaires, il est plus facile de prétendre que j'appelle une fonction pour les référencer comme une seule ligne.

Cela peut être simpliste, mais c'est surtout la façon dont j'ai utilisé static.

3
Jon Raynor