Nutzen Sie die prototypische Vererbung von JavaScript

7

JavaScript verfügt über ein klassenfreies Objektsystem, in dem Objekte Eigenschaften direkt von anderen Objekten erben. Das ist wirklich mächtig, aber klassisch ausgebildeten Programmierern unbekannt. Wenn Sie versuchen, klassische Entwurfsmuster direkt auf JavaScript anzuwenden, sind Sie frustriert. Wenn Sie jedoch lernen, mit dem Prototyp von JavaScript zu arbeiten, werden Ihre Bemühungen belohnt.
...
Es ist Lisp in Cs Kleidung.

- Douglas Crockford

Was bedeutet das für einen Spieleentwickler, der mit Canvas und HTML5 arbeitet? Ich habe mir diese Frage zu nützlichen Entwurfsmustern beim Spielen angesehen, aber die prototypische Vererbung unterscheidet sich stark von der klassischen Vererbung, und es gibt sicherlich Unterschiede in der besten Art und Weise, einige dieser allgemeinen Muster anzuwenden.

Zum Beispiel ermöglicht klassisches Erbe uns zu schaffen moveableEntityKlasse und erweitern , dass mit allen Klassen, die sie bewegt in unserer Spielwelt ( player, monster, bullet, etc.). Sicher, Sie können JavaScript stark aktivieren, um auf diese Weise zu arbeiten, aber auf diese Weise kämpfen Sie gegen seine Natur. Gibt es einen besseren Ansatz für diese Art von Problem, wenn wir die prototypische Vererbung zur Hand haben?

keithjgrant
quelle

Antworten:

8

Um eine anständige Leistung von JavaScript mit modernen JS-Engines zu erzielen, muss Code geschrieben werden, der gängige strukturelle Typisierungs- oder Ententypisierungsmuster widerspiegelt. Die strukturelle Typisierung ist leistungsfähiger als die Bereitstellung von Typen nur durch Vererbung, ändert jedoch nicht wirklich die von Spielen verwendeten Entwurfsmuster.

In C ++ oder Java, wo man normalerweise durch Vererbung tippt, hat man normalerweise tiefe Typhierarchien mit mehreren Schnittstellen / virtuellen Klassen, um MVC zu implementieren. Aber Spiele scheuen diese Art von Designmuster bereits, weil es nicht wirklich hilft, die Art von Datenspielen zu modellieren, mit denen sie umgehen.

Die Muster, die im Spieldesign am nützlichsten sind, wie Kontextobjekte, Komponenten, Fliegengewicht oder Strategie, verwenden in erster Linie keine komplizierten Vererbungshierarchien, selbst wenn sie in Sprachen wie C ++ implementiert sind. Komponenten umfassen (höchstens) eine einzelne virtuelle Klasse. Flyweight verwendet normalerweise die (umständliche) strukturelle Typisierung von C ++ über Vorlagen. Die Strategie verwendet häufig eine Art Löschung für die Leistung oder die Vernunft des Programmierers.

Die einzige Ausnahme ist das Prototypmuster selbst, das häufig in irgendeiner Form in Spielen vorkommt, insbesondere für vom Designer gesteuerte Daten. Die Verwendung von JavaScript macht dieses Muster trivial. Es ist jedoch kein besonders schwieriges Muster, zumindest schlecht in einer Sprache zu implementieren, die assoziative Datenstrukturen unterstützt. Wenn Sie JS verwenden, können Sie es häufiger verwenden, da Sie den Optimierer der zugrunde liegenden Engine nutzen können. Aber ich bin mir nicht sicher, ob dies die Art und Weise, wie man programmiert, wirklich ändern würde - ein naives Prototypmuster ist trotz seiner oft schlechten Leistung in vielen Spielen bereits an vielen Stellen vorhanden.


quelle
3
Ich habe weniger als eine Minute nach dem Posten eine positive Bewertung erhalten, die ich nicht für ausreichend Zeit halte, um sie zu lesen und zu entscheiden, ob es eine gute Antwort ist oder nicht. Ich habe mehrere Anzeichen dafür gesehen, dass manche Leute einfach Antworten hochstimmen, die lang und ohne schreckliche Grammatik geschrieben sind. Bitte tu das nicht.
Diese spezielle Antwort trifft für jeden erfahrenen Entwickler zu. Ich habe es auch fast sofort positiv bewertet, denn wenn ich es lese, sage ich: "Ja, ja, es funktioniert immer so."
Nevermind
gut gesagt! Ich hatte immer das Gefühl, dass JS sehr gut für die Art von datengesteuerten & Komponenten-Ansätzen geeignet ist, die in Spielen so verbreitet sind, mich aber nicht artikulieren konnten :)
oberhamsi
6

Wenn Sie sich wirklich mit der Semantik beschäftigen, werden Sie feststellen, dass JavaScript den meisten klassenbasierten Sprachen ein bisschen näher kommt als eine "echte" prototypische Sprache wie Self. So wie es newfunktioniert, erstellen Sie fast immer ein Objekt, das Status in seinen eigenen Feldern und Methoden in den Feldern seines Prototyps enthält. Schiel deine Augen und das ist eine Klasse.

Um wirklich prototypisch zu sein, gäbe es keine new. Sie klonen Objekte und führen eine differenzielle Vererbung durch.

Sorgen Sie sich also nicht zu sehr um die halbprototypische Natur von JavaScript. Verstehe einfach drei Teile:

  1. In den meisten Fällen handelt es sich bei Ihren Objekten im Wesentlichen um Instanzen einer "Klasse", in der der Konstruktor seine Felder definiert und die Funktionen der Konstruktoren prototypedie Methode definieren.

  2. Wenn Sie eine vertraute Einzelvererbung im Java / C # -Stil wünschen, können Sie dies erreichen, indem Sie Prototypen verketten. Die meisten JS-Frameworks (Closure, Dojo usw.) bieten einige nützliche Hilfsmethoden für die Verkabelung.

  3. Sie können jeder "Klasse" jederzeit Methoden hinzufügen. Fühlen Sie sich frei, Funktionen zu mischen, auf die Prototypen sie benötigen. Sie müssen nicht immer eine Vererbungskette und eine komplexe Hierarchie einrichten. Wenn Sie zehn Klassen haben, die dieselbe Methode benötigen, können Sie sie immer unbedingt zu diesen zehn Klassen hinzufügen.

großartig
quelle
Ich mag die dritte Art, Dinge zu tun. Beispielsweise könnten Sie eine "schädliche" Funktion haben, die ein Gesundheitsattribut und eine Damage () -Methode hinzufügt. Sie können dann Ihren anderen Code basierend auf dem Vorhandensein realer Daten / Methoden anstelle von Sentinel-Werten vom Typ "isDamageable" eingeben.
Drhayes
1
Genau richtig. Es gibt eine Reihe von JS-Frameworks, die "Mixins" bereitstellen, die so ziemlich Folgendes bewirken: Hinzufügen einer Reihe von Funktionen zu einem bestimmten Prototyp.
herrlicher