L'héritage, le polymorphisme et l'encapsulation sont les trois caractéristiques les plus importantes et les plus distinctes de la POO, et d'après eux, l'héritage a de fortes statistiques d'utilisation de nos jours. J'apprends JavaScript, et ici, ils disent tous qu'il a un héritage prototypique, et les gens partout dans le monde disent que c'est quelque chose de très différent de l'héritage classique.
Cependant, je ne peux pas comprendre quelle est leur différence du point de vue pratique? En d'autres termes, lorsque vous définissez une classe de base (prototype) puis que vous en dérivez des sous-classes, vous avez tous deux accès aux fonctionnalités de votre classe de base et vous pouvez augmenter les fonctions sur les classes dérivées. Si nous considérons ce que j'ai dit être le résultat prévu de l'héritage, alors pourquoi devrions-nous nous soucier si nous utilisons une version prototypique ou classique?
Pour me clarifier davantage, je ne vois aucune différence dans l'utilité et les modèles d'utilisation de l'héritage prototypique et classique. Cela ne m'intéresse pas à savoir pourquoi ils sont différents, car ils aboutissent tous deux à la même chose, OOAD. En quoi l'héritage prototypique est-il pratiquement (théoriquement) différent de l'héritage classique?
la source
L'héritage classique hérite du comportement, sans aucun état, de la classe parente. Il hérite du comportement au moment où l'objet est instancié.
L'héritage prototypique hérite du comportement et de l'état de l'objet parent. Il hérite du comportement et de l'état au moment où l'objet est appelé. Lorsque l'objet parent change au moment de l'exécution, l'état et le comportement des objets enfants sont affectés.
L '«avantage» de l'héritage prototypique est que vous pouvez «patcher» l'état et le comportement une fois tous vos objets instanciés. Par exemple, dans le framework Ext JS, il est courant de charger des "remplacements" qui corrigent les composants principaux du framework après que le framework a été instancié.
la source
class C(object): def m(self, x): return x*2
et puisinstance = C()
quand je coursinstance.m(3)
je reçois6
. Mais si je changeC
alorsC.m = lambda s, x: x*x
et que je cours,instance.m(3)
je comprends maintenant9
. Il en va de même si je créeclass D(C)
et modifie une méthode,C
alors toutes les instances deD
réception de la méthode modifiée sont également effectuées. Suis-je incompris ou cela signifie-t-il que Python n'a pas d'héritage classique selon votre définition?Premièrement: la plupart du temps, vous utiliserez des objets, pas les définir, et l'utilisation d'objets est la même dans les deux paradigmes.
Deuxièmement: la plupart des environnements prototypiques utilisent le même type de division que les environnements basés sur des classes - des données mutables sur l'instance, avec des méthodes héritées. Il y a donc encore très peu de différence. (Voir ma réponse à cette question de débordement de pile et les programmes d'organisation du papier sans classes . Consultez Citeseer pour une version PDF .)
Troisièmement: la nature dynamique de Javascript a une influence beaucoup plus grande que le type d'héritage. Le fait que je puisse ajouter une nouvelle méthode à toutes les instances d'un type en l'affectant à l'objet de base est bien, mais je peux faire la même chose dans Ruby, en rouvrant la classe.
Quatrièmement: les différences pratiques sont petites, tandis que le problème pratique d'oublier d'utiliser
new
est beaucoup plus important - c'est-à-dire que vous êtes beaucoup plus susceptible d'être affecté par le fait de manquer unnew
que d'être affecté par la différence entre le code prototypique et le code classique .Cela dit, la différence pratique entre l'héritage prototypique et classique est que vos choses-qui-détiennent-méthodes (classes) sont les mêmes que vos choses-qui-détiennent-données (instances). Cela signifie que vous pouvez créer vos classes au coup par coup, en utilisant tous les mêmes outils de manipulation d'objets que vous utiliseriez sur n'importe quelle instance. (C'est en fait ainsi que toutes les bibliothèques d'émulation de classe procèdent. Pour une approche pas tout à fait comme les autres, regardez Traits.js ). Ceci est principalement intéressant si vous effectuez une métaprogrammation.
la source
L'héritage prototypique en JavaScript est différent des classes de ces manières importantes:
Les constructeurs sont simplement des fonctions que vous pouvez appeler sans
new
:Il n'y a pas de variables ou de méthodes privées, au mieux vous pouvez le faire:
Dans l'exemple précédent, vous ne pouvez pas étendre la classe de manière significative si vous avez recours à de fausses variables et méthodes privées et en outre, toutes les méthodes publiques que vous avez déclarées seront recréées chaque fois qu'une nouvelle instance est créée.
la source
color
,r
,x
,y
etdrawCircle
qui sont liés à la portée lexicaleCircle
Circle.call()
en tant que constructeur? On dirait que vous essayez de décrire des "objets fonctionnels" (un terme impropre ...)