Ne pas utiliser "statique" en C #?


109

J'ai soumis une demande que j'ai écrite à d'autres architectes pour la révision du code. L'un d'entre eux m'a presque immédiatement répondu en me disant "N'utilisez pas" statique ". Vous ne pouvez pas écrire de tests automatisés avec des classes et des méthodes statiques." Statique "est à éviter."

J'ai vérifié et au moins 1/4 de mes cours sont marqués "statique". J'utilise static lorsque je ne vais pas créer une instance d'une classe car cette classe est une classe globale unique utilisée dans le code.

Il a ensuite mentionné quelque chose impliquant des techniques moqueuses, CIO / DI qui ne peuvent pas être utilisées avec du code statique. Il dit qu'il est regrettable que des bibliothèques tierces soient statiques en raison de leur caractère non testable.

Est-ce que cet autre architecte a raison?

mise à jour: voici un exemple:

APIManager - cette classe conserve les dictionnaires des API tierces que j'appelle avec la prochaine heure autorisée. Il impose les limites d'utilisation des API que de nombreuses tierces parties ont dans leurs conditions de service. Je l'utilise n'importe où j'appelle un service tiers en appelant Thread.Sleep (APIManager.GetWait ("ProviderXYZ")); avant de faire l'appel. Tout ici est thread-safe et cela fonctionne très bien avec le TPL en C #.


37
staticc'est bien; static les champs doivent être traités avec beaucoup d' attention
Marc Gravell

2
Pourquoi écrit-il des tests pour des bibliothèques tierces? Ne testez-vous pas habituellement votre propre code en supposant que les créateurs de la bibliothèque tierce ont effectué leurs tests?
Nope

3
Cette objection est un peu trop générale pour moi. Dans la plupart des cas, vous ne mocjeriez pas la classe statique, vous vous moqueriez des arguments. Champ statique où il s’agissait d’une classe agrégée à moquée, alors oui.

8
Il est clair que vos collègues sont atteints d’une maladie grave: une maladie pulmonaire aiguë érythémateuse aiguë. Ils ont besoin d'un traitement dès que possible!
SK-logic

6
Il y a une section de réponses pour fournir des réponses, je ne comprends pas pourquoi les gens commentent dans le but de donner à quelqu'un une réponse / suggestion ... Cela va à l'encontre du but de StackExchange, un commentaire serait sûrement de demander plus d'informations.
peteski

Réponses:


121

Cela dépend si les classes statiques conservent ou non l'état. Personnellement, je n’ai aucun problème avec les fonctions sans état jeté ensemble dans une classe statique.


111
Correct. Les fonctions statiques sans effets secondaires sont les fonctions les plus testables.
Robert Harvey

9
+1 à cela, mais avec une clause de sécurité: Presque tous les algorithmes abstraits sont sans état, mais cela ne signifie pas que vous devriez l'implémenter en tant que classe ou méthode statique sans état. Si vous l'implémentez de cette manière, tout le code qui l'utilise sera à peine lié à celui-ci. Cela signifie, par exemple, que si vous implémentez l'algorithme de tri en tant que méthode statique et que vous l'utilisez dans le projet, vous ne pouvez pas remplacer temporairement le tri par un autre algorithme, par exemple à des fins de test et pour réduire le problème. C'est un obstacle énorme dans de nombreux cas. En dehors de cela, statique est tout à fait correct si utilisé raisonnablement.

11
En bref: ce sont les fonctions les plus testables, mais non pas nécessairement, elles rendent l’ autre code plus testable! C'est ce que l'architecte a probablement voulu dire.

4
@ tereško: le langage C # requiert que les méthodes statiques fassent partie d'une classe statique, si vous ne souhaitez pas créer une instance de la classe pour appeler la méthode. Peut-être que vous voulez dire "instance" et non "classe".
Robert Harvey

8
@quetzalcoatl: Il est parfaitement légal de passer un délégué (un algorithme différent) à une méthode statique; les méthodes d'extension dans Linq sont toutes des méthodes statiques. Exemple: msdn.microsoft.com/en-us/library/…
Robert Harvey

93

Il est trop général à ce sujet. Il a raison, cela empêche les tests. Cependant, les staticclasses et les méthodes ont leur place et cela dépend vraiment du contexte. Sans exemples de code, vous ne pouvez pas vraiment dire.

J'utilise static lorsque je ne vais pas créer une instance d'une classe car cette classe est une classe globale unique utilisée dans le code.

Cela peut être une odeur de code grave. Pourquoi utilisez-vous les cours? Pour stocker des données? Pour accéder à une base de données? Alors il a raison. Dans ce cas, vous devriez regarder l'injection de dépendance, car une telle classe statique est en réalité un singleton implicite.

Si vous les utilisez pour des méthodes d'extension ou des aides qui ne changent pas l'état et se contentent d'agir sur les paramètres que vous fournissez, ceux-ci fonctionnent normalement.


3
+1 pour avoir mentionné que la déclaration était trop générale et mentionnait des méthodes d'extension, qui peuvent également être testées et les dépendances peuvent encore être raillées à ma connaissance.
Nope

4
Aye static en tant qu'instance de classe unique en tant que singleton implicite, cela va devenir compliqué ....

"Pour accéder à une base de données?" pourquoi pas ? si l'adaptateur de table n'est pas statique, alors créer un ensemble de données statique de classe @ fortement typée, rien de mal à cela .... à moins de prouver votre argument avec référence ou exemple?
Mathématiques

27

J'ai vérifié et au moins 1/4 de mes cours sont marqués "statique". J'utilise static lorsque je ne vais pas créer une instance d'une classe car cette classe est une classe globale unique utilisée dans le code.

La meilleure chose à faire est d'essayer de tester votre code. Essayez de concevoir des tests répétables, indépendants, simples et ne testez qu'une méthode à la fois. Essayez d'exécuter vos tests dans un ordre aléatoire différent. Pouvez-vous obtenir une construction "verte" stable?

Si oui, c'est un argument valable pour défendre votre code. Si, toutefois, vous rencontrez des difficultés, alors vous devriez peut-être utiliser des méthodes basées sur des exemples.


7
C'est le point qui m'a frappé aussi. Quelques classes de style "d'assistance" statiques et sans état sont acceptables, mais si vous avez 25% de toutes vos classes en statique, il est peu probable que vos efforts se limitent à ce cas.
Matthew Scharley

2
@ MatthewScharley - il a probablement eu 4 cours, dont l'un est Static :)
Alexus

1
Attention, si vous utilisez de telles fonctions (comme des singletons), la création ultérieure d'instances supplémentaires risque de s'avérer un travail difficile. Comme par exemple en créant une application qui gère un document, vous rencontrez des problèmes plus tard lorsque vous souhaitez gérer plusieurs documents.
Michel Keijzers

11

Les réponses déjà publiées couvrent de très bons points, mais il en manque un:

Les champs statiques ne sont jamais collectés.

Ceci est vraiment important si vous avez une application avec beaucoup de contraintes de mémoire, et ce schéma peut être très courant lorsque des personnes tentent d'implémenter un cache.

Les fonctions statiques ne sont pas aussi mauvaises, mais tout le monde a déjà couvert cela assez en détail.


10

Un des avantages de l'IoC / DI est que la plupart des interactions entre les classes sont négociées entre interfaces. Cela facilite les tests unitaires car les interfaces peuvent être simulées automatiquement ou semi-automatiquement. Par conséquent, chacune des pièces peut être testée pour les entrées et les sorties. De plus, au-delà de la testabilité, le fait de mettre des interfaces entre tous les éléments vous permet d’avoir le code le plus modulaire possible. Vous pouvez facilement remplacer une implémentation sans trop vous inquiéter des dépendances.

Comme C # n'a pas de métaclasse, une classe ne peut pas implémenter une interface utilisant des fonctionnalités statiques, aussi les fonctionnalités statiques des classes entravent-elles tout effort d'implémentation d'un modèle d'objet IoC / DI pur. C'est-à-dire que vous ne pouvez pas créer de maquette pour les tester, vous devez créer de vraies dépendances.

Si votre entreprise / projet est lourdement investi dans l'IoC, il s'agit bien sûr d'une préoccupation raisonnable, et la douleur que vous vivez est au profit de tous. D'un point de vue architectural, cependant, je ne pense personnellement pas que tout modèle devrait être suivi jusqu'à la tombe. Il y a des choses qui ont du sens à implémenter en utilisant des méthodes statiques - la stratégie de conception de singleton, par exemple. Je suis moi-même moins enclin aux classes statiques car je pense qu'elles ont tendance à perdre de plus en plus les avantages de OO, mais il arrive parfois qu'une classe de bibliothèque soit probablement l'expression plus naturelle de quelque chose qu'un moteur.


Le commentateur me rappelle les méthodes d'extension, qui doivent bien sûr être dans des classes statiques en C #. C’est légitime, et c’est un exemple de la façon dont IoC pur ne fonctionne pas très bien en C #, du moins si vous essayez de tirer parti de l’ampleur du langage.


1
Si une classe est rendue statique pour les bonnes raisons et correctement implémentée, comme par exemple des méthodes d'extension, elle reste testable dans la mesure où elle n'aurait aucune dépendance externe, qu'elle serait autonome et ne devrait donc pas nécessiter de simulation. Le besoin d'une interface ne devrait-il pas être motivé par la conception afin de remplir au mieux une exigence de l'entreprise et non dans le but de conserver un projet IoC / DI pur?
Nope

1
Vous et moi sommes d'accord sur le point général selon lequel vous devez choisir le bon outil pour le bon travail et ne pas être menotté par la philosophie. Si, toutefois, votre projet de code IoC / DI pur est bien ancré dans la culture, cela fera aussi mal que de convertir une solution traditionnellement descendante en système IoC / DI. L’ingénierie doit prendre en compte les coûts de transition. À propos, je ne pense pas que les méthodes de vulgarisation vous y amènent tout à fait. Je pense qu'une meilleure solution pour le comportement IoCish avec des classes statiques serait d'avoir plusieurs classes choisies entre la compilation et les directives de préprocesseur, style C
jwrush

1
Er. Je suis stupide. Vous vouliez dire une classe statique pour les méthodes d'extension HOLDING, ce qui, bien sûr, explique comment vous devez les faire. Oui, bien sûr, vous voulez une classe statique à cette fin. Cela m'a échappé: cela montre que C # n'était pas destiné à IoC. :)
Jwrush

Oui, vous avez raison, si une culture existante dans un projet existant existait, ce serait plus dommageable que d'aider à changer la façon dont les choses se font.
Nope

5

Les classes statiques sont parfois mal utilisées et devraient être:

  • un singleton (où la classe non statique a un membre statique et une variable d'instance statique publique pour le récupérer / le créer une seule fois.
  • une méthode dans une autre classe (où l'état compte). Si un membre n'utilise aucune donnée de cette classe, il ne devrait probablement pas en faire partie.

Il peut également s'agir d'une fonction dite "d'utilitaire" et d'une partie d'une classe d'utilitaires. Les classes d'utilitaires sont des classes qui ne contiennent que des méthodes statiques et servent de fonctions d'assistance sans contexte.


@topomorto Parce que la classe ne devrait pas être instanciée par son constructeur entraînant plusieurs objets / instances, mais par une méthode spéciale (normalement instance ()) <qui retourne toujours la même instance, instanciée après le premier appel à instance ().
Michel Keijzers

@topomorto Je viens de vérifier et vous avez tout à fait raison, seuls certains membres sont statiques (la variable d'instance et la fonction d'instance). Je changerai ma réponse en conséquence; merci de mentionner.
Michel Keijzers

4

Les méthodes statiques sont faciles à utiliser et ont la place qui leur revient dans la programmation. Il semble que votre architecte dispose d'un cadre de test qui ne prend pas complètement en charge les méthodes statiques. Si votre code fait partie d'un projet plus important, il est important de respecter les directives de l'architecte. Cependant, ne laissez pas ce projet vous dissuader d'utiliser des méthodes statiques lorsque cela est approprié.


1

J'utilise des propriétés statiques pour des éléments communs à toutes les instances d'une classe. Et j'ai utilisé des méthodes statiques pour obtenir des groupes d'objets de classe. Je ne suis en aucun cas un expert, mais cela a fonctionné pour moi jusqu'à présent.

Exemple PHP:

class vendorData {
  private static $data_table = 'vendor_data'; // static property
  private $id; // instance property
  private $name; // instance property

  public function __construct($vendor_id) {
    if(!self::validId($vendor_id) ) { // static method
      return false; // id doesn't exist
    }
    $this->id = $vendor_id; // id has been validated
    $this->getProperties(); // object method
  }

  private static function validId($vendor_id) {
    // send db query to find if the id exists
    // return true/false;
  }

  private function getProperties() { // object method
    $sql = "SELECT * FROM `{self::$data_table}` // using static property
        WHERE `id` = {$this->id}"; // using object instance property
    // get resultset
    foreach($result as $property => $value) {
      $this->$property = $value; // object instance properties all set
    }
  }

  // and here
  public static function getBy($property,$value) { // static method to return object array
    $sql = "SELECT `id` FROM `{self::$data_table}` // using static property
      WHERE `$property` = '$value'";
    // send query, get $ids array
    $obj_array = array();
    foreach($ids as $id) {
      // create array of current class objects using special static keyword
      // meaning of static here is different than in property/method declarations
      $obj_array[$id] = new static($id);
    }
    return $obj_array;
  }
}

1

Je dirai que leurs principes sont corrects mais que la déclaration (n'utilisez pas de statique) peut être fausse. Combien coûte votre couverture de code? si le nombre est élevé et que vous êtes à l'aise avec les tests unitaires de votre application, vous êtes ok. Si non, alors je suggérerais de revoir le code. Vous pouvez trouver que les classes statiques sont la raison ou non, cela dépendra de beaucoup de choses.


-3

Les classes utilisant des méthodes statiques abusent des principes de la programmation orientée objet. Ce n'est pas déjà une POO, c'est COP - une programmation orientée classe.

Ils ont rarement une "personnalité" claire (j'utilise ma métaphore humaine préférée ici), ou une identité. Donc, ils ne savent pas qui ils sont. Ce point suffit à lui seul à se débarrasser de ce concept en POO, mais il y en a plus.

Le suivant est une conséquence du premier point. Étant donné que ces classes ne savent pas qui elles sont, elles ont tendance à être très grandes.

La troisième rend votre code absolument non maintenable. L'utilisation de méthodes statiques introduit des dépendances cachées . Ils apparaissent partout et vous ne savez jamais ce qui se passe dans votre classe. Vous ne pouvez pas en être sûr simplement en regardant la signature du constructeur.

Lentement mais inévitablement, votre code devient de moins en moins cohérent, car les dépendances cachées sont mal contrôlées. Ils semblent invisibles. Et c'est si facile d'en ajouter un autre! Vous ne devez modifier aucune signature de méthode. Tout ce que vous avez à faire est d'appeler une méthode statique. Et quel code laid suit ...

Ok, vous avez probablement déjà deviné. Le couplage serré est souvent associé à une faible cohésion. Si de nombreux clients utilisent une classe, le couplage se resserre. Et il y a une grande séduction à utiliser une classe ou une méthode déjà écrite qui ne nécessite qu'une correction minime. Un seul paramètre indicateur-méthode.

Quoi utiliser à la place des méthodes statiques? Eh bien, ma suggestion est la POO. Pourquoi ne pas essayer?

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.