Vererbung, Polymorphismus und Verkapselung sind die drei wichtigsten Merkmale von OOP, und von diesen hat Vererbung heutzutage eine hohe Nutzungsstatistik. Ich lerne JavaScript und hier sagen alle, dass es eine prototypische Vererbung hat, und die Leute sagen überall, dass es etwas ganz anderes ist als die klassische Vererbung.
Ich kann jedoch nicht verstehen, worin der Unterschied zum praktischen Gebrauch besteht. Mit anderen Worten, wenn Sie eine Basisklasse (einen Prototyp) definieren und dann einige Unterklassen daraus ableiten, haben Sie beide Zugriff auf Funktionalitäten Ihrer Basisklasse und können Funktionen für die abgeleiteten Klassen erweitern. Wenn wir bedenken, was ich als beabsichtigtes Ergebnis der Vererbung bezeichnete, warum sollte es uns dann etwas ausmachen, wenn wir eine prototypische oder klassische Version verwenden?
Um mich selbst klarer zu machen, sehe ich keinen Unterschied in der Nützlichkeit und den Nutzungsmustern der prototypischen und klassischen Vererbung. Dies hat zur Folge, dass ich kein Interesse daran habe zu erfahren, warum sie unterschiedlich sind, da beide dasselbe Ergebnis haben, OOAD. Wie praktisch (nicht theoretisch) unterscheidet sich die prototypische Vererbung von der klassischen Vererbung?
quelle
Die klassische Vererbung erbt das Verhalten ohne Status von der übergeordneten Klasse. Es erbt das Verhalten in dem Moment, in dem das Objekt instanziiert wird.
Die prototypische Vererbung erbt das Verhalten und den Status des übergeordneten Objekts. Es erbt das Verhalten und den Zustand zum Zeitpunkt des Objektaufrufs. Wenn sich das übergeordnete Objekt zur Laufzeit ändert, sind der Status und das Verhalten der untergeordneten Objekte betroffen.
Der "Vorteil" der prototypischen Vererbung besteht darin, dass Sie den Status und das Verhalten "patchen" können, nachdem alle Ihre Objekte instanziiert wurden. Beispielsweise werden im Ext JS-Framework häufig "Überschreibungen" geladen, die die Kernkomponenten des Frameworks nach der Instanziierung des Frameworks patchen.
quelle
class C(object): def m(self, x): return x*2
und dann,instance = C()
wenn ich renne,instance.m(3)
bekomme ich6
. Aber wenn ich mich dannC
so ändereC.m = lambda s, x: x*x
und ich renneinstance.m(3)
bekomme ich jetzt9
. Das gleiche gilt, wenn ichclass D(C)
eine Methode erstelle und ändere,C
dannD
empfangen auch alle Instanzen der geänderten Methode. Verstehe ich das falsch oder bedeutet das, dass Python keine klassische Vererbung gemäß Ihrer Definition hat?Erstens: Meistens werden Sie Objekte verwenden, nicht definieren, und die Verwendung von Objekten ist unter beiden Paradigmen gleich.
Zweitens: Die meisten prototypischen Umgebungen verwenden dieselbe Art der Unterteilung wie klassenbasierte Umgebungen - veränderbare Daten auf der Instanz mit vererbten Methoden. Es gibt also wieder sehr wenig Unterschied. (Siehe meine Antwort auf diese Stapelüberlauffrage und die Selbstorganisationsprogramme ohne Klassen . Eine PDF-Version finden Sie bei Citeseer .)
Drittens: Die Dynamik von Javascript hat einen viel größeren Einfluss als die Art der Vererbung. Die Tatsache, dass ich allen Instanzen eines Typs eine neue Methode hinzufügen kann, indem ich sie dem Basisobjekt zuordnete, ist ordentlich, aber ich kann dasselbe in Ruby tun, indem ich die Klasse erneut öffne.
Viertens: Die praktischen Unterschiede sind gering, während das praktische Problem des Vergessens der Benutzung
new
viel größer ist - das heißt, Sie sind viel wahrscheinlicher davon betroffen, wenn Sie ein vergessen habennew
als Sie vom Unterschied zwischen prototypischem und klassischem Code betroffen zu sein .Der praktische Unterschied zwischen prototypischer und klassischer Vererbung besteht jedoch darin, dass Ihre Methoden (Klassen) für das Halten von Dingen mit den Daten (Instanzen) für das Halten von Dingen identisch sind. Dies bedeutet, dass Sie Ihre Klassen aufbauen können Stück für Stück mit den gleichen Werkzeugen zur Objektbearbeitung, die Sie für jede Instanz verwenden würden. (Dies ist in der Tat die Vorgehensweise aller Klassenemulationsbibliotheken . Schauen Sie sich Traits.js an, um einen Ansatz zu finden, der nicht allen anderen sehr ähnlich ist. ) Dies ist vor allem dann interessant, wenn Sie eine Metaprogrammierung durchführen.
quelle
Die prototypische Vererbung in JavaScript unterscheidet sich in folgenden wichtigen Punkten von Klassen:
Konstruktoren sind einfach Funktionen, die Sie aufrufen können, ohne
new
:Es gibt keine privaten Variablen oder Methoden, bestenfalls können Sie dies tun:
Im vorherigen Beispiel können Sie die Klasse nicht sinnvoll erweitern, wenn Sie auf gefälschte private Variablen und Methoden zurückgreifen. Außerdem werden alle von Ihnen deklarierten öffentlichen Methoden jedes Mal neu erstellt, wenn eine neue Instanz erstellt wird.
quelle
color
,r
,x
,y
unddrawCircle
, die den lexikalischen Geltungsbereich gebunden sindCircle
Circle.call()
als Konstrukteur? Es sieht so aus, als ob Sie versuchen, "funktionale Objekte" zu beschreiben (eine falsche Bezeichnung ...)