Quelle est la différence entre les deux méthodes UpdateSubject ci-dessous? Je pensais que l'utilisation de méthodes statiques est meilleure si vous voulez simplement opérer sur les entités. Dans quelles situations dois-je utiliser des méthodes non statiques?
public class Subject
{
public int Id {get; set;}
public string Name { get; set; }
public static bool UpdateSubject(Subject subject)
{
//Do something and return result
return true;
}
public bool UpdateSubject()
{
//Do something on 'this' and return result
return true;
}
}
Je sais que je vais recevoir de nombreux coups de pied de la communauté pour cette question vraiment ennuyeuse mais je ne pouvais pas m'empêcher de la poser.
Cela devient-il impraticable lorsqu'il s'agit d'héritage?
Mise à jour:
Cela se produit sur notre lieu de travail maintenant. Nous travaillons sur une application web asp.net de 6 mois avec 5 développeurs. Notre architecte a décidé que nous utilisons toutes les méthodes statiques pour toutes les API. Son raisonnement étant des méthodes statiques sont légers et il profite aux applications Web en réduisant la charge du serveur.
Je vais aborder les problèmes les plus évidents des méthodes statiques avec des paramètres "this" explicites:
Vous perdez la répartition virtuelle et par la suite le polymorphisme. Vous ne pouvez jamais remplacer cette méthode dans une classe dérivée. Bien sûr, vous pouvez déclarer une méthode new
(static
) dans une classe dérivée, mais tout code qui y accède doit connaître la hiérarchie de classe entière et effectuer une vérification et une conversion explicites, ce qui est précisément ce que OO est censé éviter.
Une sorte d'extension # 1, vous ne pouvez pas remplacer les instances de la classe par une interface , car les interfaces (dans la plupart des langues) ne peuvent pas déclarer static
méthodes.
La verbosité inutile. Quel est le plus lisible: Subject.Update(subject)
ou simplement subject.Update()
?
Vérification d'argument. Cela dépend encore une fois de la langue, mais beaucoup compileront une vérification implicite pour s'assurer que l'argument this
n'est pas null
afin d'empêcher un bogue de référence nul de créer des conditions d'exécution dangereuses (type de tampon envahi). N'utilisant pas de méthodes d'instance, vous devez ajouter cette vérification explicitement au début de chaque méthode.
C'est déroutant. Quand un programmeur normal et raisonnable voit une méthode static
, il va naturellement supposer qu'elle doesn 't nécessite une instance valide (sauf s'il faut plusieurs instances, comme une méthode de comparaison ou d'égalité, ou s'il est censé pouvoir fonctionner sur les références null
). Voir les méthodes statiques utilisées de cette façon va nous faire faire une double ou peut-être une triple prise, et après la 4e ou la 5e fois, nous serons stressés et en colère et Dieu vous aidera si nous connaissons votre adresse personnelle.
C'est une forme de duplication. Ce qui se passe réellement lorsque vous appelez une méthode d'instance, c'est que le compilateur ou le moteur d'exécution recherche la méthode dans la table des méthodes du type et l'invoque en utilisant this
comme argument. Vous réimplémentez essentiellement ce que le compilateur fait déjà. Vous violez SEC , répétant le même paramètre encore et encore dans différentes méthodes lorsqu'il n'est pas nécessaire.
Il est difficile de concevoir une bonne raison de remplacer les méthodes d'instance par des méthodes statiques. S'il vous plait, ne le faites pas.
Vous avez à peu près décrit exactement comment vous faites OOP en C, dans lequel seules les méthodes statiques sont disponibles, et "this" est un pointeur de structure. Et oui, vous pouvez exécuter le polymorphisme au moment de l'exécution dans C en spécifiant un pointeur de fonction pendant la construction à stocker comme un élément de la structure. Les méthodes d'instance disponibles dans d'autres langages ne sont que du sucre syntaxique qui fait exactement la même chose sous le capot. Certains langages, comme le python, sont à mi-chemin entre, où le paramètre "self" est explicitement répertorié, mais une syntaxe spéciale pour l'appeler gère pour vous l'héritage et le polymorphisme.
Le problème avec la méthode statique survient au moment où vous avez besoin d'une sous-classe.
Les méthodes statiques ne peuvent pas être remplacées dans les sous-classes, par conséquent vos nouvelles classes ne peuvent pas fournir de nouvelles implémentations des méthodes, les rendant moins utiles.
Si vous déclarez une méthode static
, vous n'avez pas besoin d'instancier un objet de la classe (en utilisant le mot clé new
) pour exécuter la méthode. Cependant, vous ne pouvez pas faire référence à des variables membres sauf si elles sont également statiques, auquel cas ces variables membres appartiennent à la classe, pas un objet instancié spécifique de la classe .
Autrement dit, le mot clé static
fait qu'une déclaration fait partie de la définition de classe, elle devient donc n point de référence unique dans toutes les instances de la classe (objets instanciés à partir de la classe) .
Il s'ensuit donc que si vous voulez plusieurs copies en cours d'exécution de votre classe et que vous ne voulez pas que l'état (variables membres) soit partagé entre toutes vos copies en cours d'exécution (c'est-à-dire que chaque objet possède son propre état unique), alors vous ne peut pas déclarer ces variables membres statiques.
En général, vous ne devez utiliser les classes et méthodes static
que lorsque vous créez des méthodes utilitaires qui acceptent un ou plusieurs paramètres, et renvoyez un objet quelconque, sans aucun effet secondaire (ie modifications des variables d'état dans la classe)
La raison pour laquelle les gens soutiennent que "les méthodes statiques montrent une mauvaise conception" n'est pas nécessairement due aux méthodes, ce sont en fait des données statiques, implicites ou explicites. Par implicite, je veux dire TOUT état dans le programme qui n'est pas contenu dans la ou les valeurs de retour ou les paramètres. La modification de l'état dans une fonction statique est un retour à la programmation procédurale. Cependant, si la fonction ne modifie pas l'état, ou délègue la modification d'état aux fonctions d'objet composant, c'est en fait plus un paradigme fonctionnel que procédural.
Si vous ne changez pas d'état, les méthodes et classes statiques peuvent présenter de nombreux avantages. Il est ainsi beaucoup plus facile de s'assurer qu'une méthode est pure et donc exempte d'effets secondaires et d'éventuelles erreurs sont entièrement reproductibles. Il garantit également que différentes méthodes dans plusieurs applications utilisant une bibliothèque partagée peuvent être assurées qu'elles obtiendront les mêmes résultats avec la même entrée, ce qui facilite à la fois le suivi des erreurs et les tests unitaires.
En fin de compte, il n'y a aucune différence dans la pratique entre les objets surdimensionnés couramment vus tels que "StateManager" et les données statiques ou globales. L'avantage des méthodes statiques utilisées correctement est qu'elles peuvent indiquer l'intention de l'auteur de ne pas modifier l'état aux réviseurs ultérieurs.
C'est une question très intéressante qui a tendance à avoir des réponses très différentes selon la communauté que vous lui posez. D'autres réponses semblent être C # ou Java biais: un langage de programmation qui est (principalement) purement orienté objet et qui a une sorte de vision idiomatique de l'orientation de l'objet.
Dans d'autres communautés, comme C++, l'orientation objet est interprétée avec plus de libéralité. Certains connaissent bien les experts qui ont étudié le sujet et, en fait, concluent que les fonctions libres améliorent l'encapsulation (c'est moi qui souligne):
Nous avons maintenant vu qu'un moyen raisonnable de mesurer la quantité d'encapsulation dans une classe est de compter le nombre de fonctions qui pourraient être rompues si l'implémentation de la classe change. Cela étant, il devient clair qu'une classe avec n fonctions membres est plus encapsulée qu'une classe avec n + 1 fonctions membres. Et cette observation est ce qui justifie mon argument pour préférer les fonctions non-membres non-amis aux fonctions membres
Scott Meyers
Pour ceux qui ne connaissent pas la terminologie C++:
Maintenant, pour répondre à votre question:
Je ne peux pas simplement utiliser toutes les méthodes statiques?
Non, vous ne devez pas toujours utiliser des méthodes statiques.
Mais, vous devez les utiliser chaque fois que vous avez seulement besoin d'utiliser l'API publique d'une classe.
Selon la langue et ce que vous essayez de faire, la réponse peut être qu'il n'y a pas beaucoup de différence, mais la version static
a un peu plus d'encombrement.
Comme le suggère votre exemple de syntaxe Java ou C #, je pense que Thorbjørn Ravn Andersen a raison de souligner le problème primordial (avec liaison tardive). Avec une méthode statique, il n'y a pas de paramètre "spécial" pour la liaison tardive doit être basée, vous ne pouvez donc pas avoir de liaison tardive.
En effet, une méthode statique n'est qu'une fonction dans un module, ce module ayant le même nom que la classe - ce n'est pas vraiment une méthode OOP).
Vous êtes en train de vaincre la totalité des objets lorsque vous faites cela. Il y a une bonne raison pour laquelle nous sommes passés du code procédural au code orienté objet.
Je voudrais JAMAIS déclarer une méthode statique qui a pris le type de classe comme paramètre. Cela rend le code plus complexe sans aucun gain.
Il y a beaucoup de bonnes réponses ici, et elles sont beaucoup plus perspicaces et bien informées que tout ce que je pourrais trouver comme réponse, mais je pense qu'il y a un petit quelque chose qui n'est pas abordé:
"Notre architecte a décidé que nous utilisons toutes les méthodes statiques pour toutes les API. Son raisonnement étant les méthodes statiques sont légers et cela profite aux applications Web en réduisant la charge du serveur."
(L'accent gras est le mien)
Mon 2c sur cette partie de la question est la suivante:
Théoriquement, ce qui est dit est vrai: appeler une méthode statique n'a que le surcoût d'invoquer réellement cette méthode. L'appel d'une méthode (statique) non statique a le surcoût supplémentaire d'instancier d'abord l'objet et, à un moment donné, de détruire l'instance (manuellement ou via une forme de collecte automatique des déchets, selon la plate-forme utilisée).
Le jeu un peu de l'avocat du diable à ce sujet: nous pouvons aller encore plus loin et dire des choses telles que:
cela peut devenir vraiment mauvais si une instance est créée pour chaque invocation de la méthode (instance) (au lieu de simplement la laisser statique et l'appeler comme ça)
en fonction de la complexité du constructeur, de la hiérarchie des types, d'autres membres d'instance et d'autres facteurs inconnus, la surcharge supplémentaire de l'appel de méthode non statique peut varier et devenir très importante
En vérité, à mon humble avis, les points ci-dessus (et l'approche générale de "utilisons la statique car ils sont plus rapides") sont des arguments/évaluations de l'homme de paille:
si le code est bon et, plus spécifique à cet argument, si les instances sont créées uniquement lorsque cela est nécessaire (et détruites de manière optimale), vous n'obtenez pas de surcharge supplémentaire en utilisant des méthodes d'insance le cas échéant (car si vous créer uniquement les objets nécessaires, ceux-ci auraient été créés même si cette méthode avait été déclarée statique certains où autre = même surcharge d'instanciation)
en abusant de cette façon de la déclaration des méthodes statiques, il est possible de masquer certains problèmes avec votre code en ce qui concerne la façon dont les instances sont créées (puisque la méthode est statique, un code d'instanciation incorrect peut passer inaperçu plus tard, et ce n'est jamais bon).