2008-10-14 24 views
27

Je travaille sur un projet en C#. Le programmeur précédent ne connaissait pas la programmation orientée objet, donc la plupart du code est dans des fichiers énormes (nous parlons de 4-5000 lignes) répartis sur des dizaines et parfois des centaines de méthodes, mais une seule classe. Refactoriser un tel projet est une entreprise énorme, et j'ai donc appris à vivre avec pour le moment.Performance de l'utilisation de méthodes statiques vs instanciation de la classe contenant les méthodes

Chaque fois qu'une méthode est utilisée dans l'un des fichiers de code, la classe est instanciée et la méthode est appelée sur l'instance de l'objet.

Je me demande s'il y a des pénalités de performance notables en procédant ainsi? Devrais-je rendre toutes les méthodes statiques "pour l'instant" et, surtout, l'application en bénéficiera-t-elle de quelque manière que ce soit?

+0

Je pense que cela devrait être migré vers cs.SE –

Répondre

24

De here, un appel statique est 4 à 5 fois plus rapide que la construction d'une instance à chaque fois que vous appelez une méthode d'instance. Cependant, nous ne parlons toujours que de dizaines de nanosecondes par appel, vous ne remarquerez donc aucun avantage à moins que vous ayez des boucles très serrées appelant une méthode des millions de fois, et que vous puissiez obtenir le même avantage en construisant une instance cette boucle et la réutiliser.

Étant donné que vous devez modifier chaque site d'appel pour utiliser la méthode nouvellement statique, il vaut probablement mieux passer votre temps à refactoriser progressivement.

+0

article impressionnant. J'ai juste commencé à le faire parce que je m'intéressais à ce qui est plus rapide. "While object.read" ou For-Loop et IF. Et cet article est juste la chose parfaite après ma recherche personnelle. Très agréable. Maintenant, j'ai un très gros objet qui est accédé à de nombreux endroits et je me suis demandé si la météo valait la peine de le passer méthode par méthode à l'endroit où il doit aller ou simplement créer une classe de variables globales et y accéder. Difficile de tester ce qui sera plus rapide ...? :( –

2

Il me semble idiot de créer un objet JUSTE afin que vous puissiez appeler une méthode qui n'a apparemment pas d'effets secondaires sur l'objet (à partir de votre description je suppose que cela). Il me semble qu'un meilleur compromis serait d'avoir plusieurs objets globaux et de les utiliser. De cette façon, vous pouvez placer les variables qui sont normalement globales dans les classes appropriées afin qu'elles aient une portée légèrement plus petite. À partir de là, vous pouvez déplacer lentement la portée de ces objets pour qu'ils soient de plus en plus petits jusqu'à ce que vous ayez une conception OOP correcte.

Ensuite, l'approche que I utiliserait probablement est différente;). Personnellement, je me concentrerais probablement sur les structures et les fonctions qui fonctionnent sur eux et essayer de les convertir en classes avec des membres peu à peu. En ce qui concerne l'aspect performance de la question, les méthodes statiques devraient être légèrement plus rapides (mais pas beaucoup) car elles n'impliquent pas la construction, le passage et la déconstruction d'un objet.

3

Je pense que vous avez partiellement répondu à cette question de la façon dont vous l'avez posée: y a-t-il des pénalités de performance notables dans le code que vous avez? Si les pénalités ne sont pas perceptibles, vous n'avez pas nécessairement besoin de faire quoi que ce soit. (Bien qu'il soit évident que la base de code bénéficierait de façon spectaculaire d'un refactorisant graduel dans un modèle OO respectable).

Je suppose que ce que je dis est, un problème de performance est seulement un problème lorsque vous remarquez que c'est un problème.

7

Cela dépend de ce que contient cet objet - si "l'objet" n'est qu'un ensemble de fonctions, ce n'est probablement pas la fin du monde. Mais si l'objet contient un tas d'autres objets, alors l'instancier va appeler tous leurs constructeurs (et destructeurs, quand il est supprimé) et vous pouvez obtenir une fragmentation de mémoire et ainsi de suite.

Cela dit, il ne semble pas que la performance est votre plus gros problème en ce moment.

9

J'ai eu affaire à un problème similaire où je travaille. Le programmeur avant moi a créé 1 classe de contrôleur où toutes les fonctions BLL ont été déversées.

Nous sommes actuellement en train de reconcevoir le système et avons créé de nombreuses classes de contrôleurs en fonction de ce qu'ils sont supposés contrôler, par ex.

UserController, GeographyController, ShoppingController ...

l'intérieur de chaque classe de contrôleur, ils ont des méthodes statiques qui font des appels à mettre en cache ou le DAL en utilisant le modèle singleton.

Cela nous a donné 2 avantages principaux. Il est légèrement plus rapide (environ 2-3 fois plus rapide mais parlait nanosecondes ici, P). L'autre est que le code est beaucoup plus propre

-à-dire

ShoppingController.ListPaymentMethods() 

au lieu de

new ShoppingController().ListPaymentMethods() 

Je pense qu'il est logique d'utiliser des méthodes statiques ou des classes si la classe ne maintient pas l'état .

5

Vous devez déterminer les objectifs de la réécriture. Si vous voulez avoir du code OO maintenable & extensible testable, vous pouvez essayer d'utiliser des objets et leurs méthodes d'instance. Après tout, c'est de la programmation orientée objet que nous parlons ici, pas de la programmation orientée vers la classe.

Il est très simple de faux et/ou des objets fantaisie lorsque vous définissez des classes qui implémentent des interfaces et vous exécutez les méthodes d'instance. Cela rend les tests unitaires approfondis rapides et efficaces. En outre, si vous devez suivre de bons principes OO (voir SOLID au http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29) et/ou utiliser des modèles de conception, vous ferez certainement beaucoup de développement basé sur une interface, et n'utilisez pas beaucoup de méthodes statiques.

Quant à cette suggestion:

Il me semble stupide de créer un objet juste pour que vous pouvez appeler une méthode qui n'a apparemment pas d'effets secondaires sur l'objet (d'après votre description, je suppose que ce).

Je vois cela beaucoup dans les magasins dot net et me viole cette encapsulation, un concept clé OO. Je ne devrais pas être en mesure de dire si une méthode a des effets secondaires, que la méthode soit statique ou non. En plus de rompre l'encapsulation, cela signifie que vous devrez changer les méthodes de statique en instance si/quand vous les modifiez pour avoir des effets secondaires. Je vous suggère de lire le principe Open/Closed pour celui-ci et de voir comment l'approche suggérée, citée ci-dessus, fonctionne dans cet esprit. Rappelez-vous cette vieille châtaigne, «l'optimisation prématurée est la racine de tout mal». Je pense que dans ce cas, cela signifie ne pas sauter à travers les cerceaux en utilisant des techniques inappropriées (c'est-à-dire la programmation orientée classe) jusqu'à ce que vous sachiez que vous avez un problème de performance. Même alors déboguer le problème et chercher le plus approprié.

2

Les méthodes statiques sont beaucoup plus rapides et utilisent beaucoup moins de mémoire. Il y a cette idée fausse que c'est juste un peu plus rapide. C'est un peu plus rapide tant que vous ne le mettez pas sur des boucles. BTW, certaines boucles semblent petites mais ne le sont vraiment pas parce que l'appel de méthode contenant la boucle est aussi une autre boucle. Vous pouvez indiquer la différence de code qui effectue les fonctions de rendu. Beaucoup moins de mémoire est malheureusement vraie dans de nombreux cas. Une instance permet un partage facile des informations avec les méthodes soeurs. Une méthode statique demandera l'information quand il en a besoin. Mais comme dans la conduite des voitures, la vitesse apporte la responsabilité. Les méthodes statiques ont généralement plus de paramètres que leur contrepartie d'instance. Étant donné qu'une instance prendrait soin de mettre en cache des variables partagées, vos méthodes d'instance sembleront plus belles.

ShapeUtils.DrawCircle(stroke, pen, origin, radius); 

ShapeUtils.DrawSquare(stroke, pen, x, y, width, length); 

VS

ShapeUtils utils = new ShapeUtils(stroke,pen); 

util.DrawCircle(origin,radius); 

util.DrawSquare(x,y,width,length); 

Dans ce cas, chaque fois que les variables d'instance sont utilisées par toutes les méthodes la plupart du temps, les méthodes d'instance sont assez la peine. Les instances ne concernent PAS L'ÉTAT, mais le PARTAGE, bien que l'ÉTAT COMMUN soit une forme naturelle de PARTAGE, elles ne sont PAS LES MÊMES. La règle générale est la suivante: si la méthode est étroitement liée à d'autres méthodes --- ils s'aiment tellement que quand on est appelé, l'autre doit être appelé aussi et ils partagent probablement la même tasse d'eau-- -, il devrait être fait instance. Traduire des méthodes statiques en méthodes d'instance n'est pas si difficile. Vous avez seulement besoin de prendre les paramètres partagés et de les mettre comme variables d'instance. L'inverse est plus difficile.

Ou vous pouvez créer une classe de proxy qui établira un pont entre les méthodes statiques. Bien que cela puisse paraître plus inefficace en théorie, la pratique raconte une histoire différente. C'est parce que chaque fois que vous devez appeler un DrawSquare une fois (ou dans une boucle), vous allez directement à la méthode statique. Mais quand vous l'utiliserez encore et encore avec DrawCircle, vous utiliserez le proxy d'instance. Un exemple est les classes System.IO FileInfo (instance) vs File (static).

Les méthodes statiques sont testables. En fait, encore plus testable que l'instance une fois. La méthode GetSum (x, y) serait très testable non seulement pour le test unitaire, mais aussi pour le test de charge, le test intégré et le test d'utilisation. Les méthodes d'instance sont bonnes pour les tests d'unités mais horribles pour tous les autres tests (ce qui compte plus que les tests d'unités BTW) c'est pourquoi nous avons tant de bugs ces jours-ci. La chose qui rend toutes les méthodes indétachables sont des paramètres qui n'ont pas de sens comme (Sender s, EventArgs e) ou un état global comme DateTime.Now. En fait, les méthodes statiques sont si bonnes au testabilité que vous voyez moins de bogues dans le code C d'une nouvelle distribution Linux que votre programmeur OO moyen (il est plein de s *** je sais).