Vererbung und Erweitern von Objekten mit JavaScript

Wenn Sie mit der objektorientierten Programmierung vertraut sind, sind Sie wahrscheinlich mit Unterklassen und Vererbung vertraut. Vererbung wurde jedoch zu einem schlechten Ruf. Ich glaube, das liegt daran, dass einige Entwickler es als Catch-All-Lösung betrachten, wenn Sie ein Programm ändern müssen. Das Problem dabei ist, dass Klassenhierarchien unüberschaubar werden können. 

Es gibt andere Entwurfsmuster, mit denen wir unsere Apps verständlicher machen und für Änderungen bereit sind. Ich werde Ihnen Beispiele zeigen, wie Sie Vererbung und das Dekorations- und Verbundmuster verwenden können, um das Design Ihres Programms zu verbessern.

Erbe

Hinter der Vererbung steht die Idee, dass ein Objekt eine spezialisierte Version eines anderen Objekts ist. Es gibt eine übergeordnete Klasse (auch Superklasse genannt), die die Basiseigenschaften unseres Objekts definiert. Und es gibt eine untergeordnete Klasse (Unterklasse), die die Eigenschaften der übergeordneten Klasse erbt. 

Ein Beispiel für Vererbung sind ein Hund und ein Pudel. Alle Hunde haben bestimmte Eigenschaften wie vier Beine und die Fähigkeit zu bellen. Ein Pudel „ist“ eine Art Hund. Ein SUV ist ein Fahrzeug. Ein Kreis ist eine Form. So würde unsere Klassenhierarchie aussehen, wenn wir ein Programm zum Erstellen von Formen entwerfen.

Der Vorteil einer Shape-Klasse besteht darin, dass wir die Eigenschaften und Methoden, die wir in anderen Klassen definiert haben, wiederverwenden können. 

Beachten Sie, dass die getArea Die Methode wurde in jeder unserer Unterklassen neu definiert. Wir mussten diese Methode nicht neu definieren, haben es jedoch getan, um die Implementierung der Methode durch unsere Eltern zu ersetzen. Das liegt daran, dass jede Form eine eigene Art hat, die Fläche zu berechnen. 

Das Überschreiben einer übergeordneten Methode in einer untergeordneten Klasse ist ein Beispiel für Polymorphismus. Polymorphismus ist die Fähigkeit von Objekten, mehrere Formen zu haben. Es ermöglicht Unterklassen, über Methoden zu verfügen, die denselben Namen wie ihre Oberklasse haben, jedoch unterschiedliche Implementierungen haben.  

Dies ist ein Beispiel dafür, wie unser Code zum Erstellen einer Shape- und Circle-Unterklasse aussehen würde:

Klasse Shape Konstruktor (x, y) this.xPosition = x; this.yPosition = y;  getArea () … Klasse Circle erweitert Shape Konstruktor (x, y, Radius) super (x, y, Radius); this.radius = radius getArea () … let kreis = neuer Kreis (1,2,3);

Einer der Nachteile dieser Entwurfsauswahl besteht darin, dass, wenn Sie entscheiden, dass die übergeordnete Klasse geändert werden muss, auch die Unterklassen zusammen mit allen von uns erstellten Objekten geändert werden müssen. 

Angenommen, wir haben später entschieden, dass es besser ist, die x- und y-Parameter der Shape-Klasse durch ein Objekt zu ersetzen. Daher müssen wir den Konstruktor für alle unsere Unterklassen und die Argumente für jedes Objekt, das wir instanziiert haben, ändern.

Wir können sehen, wie dies leicht problematisch werden kann. Wir müssten sicherstellen, dass wir unser Design gleich beim ersten Mal richtig gemacht haben, um eine Änderung zu vermeiden. Aber das ist weder praktisch noch das, wonach wir streben sollten. Ein Programm ist eine sich ständig weiterentwickelnde Einheit, und es ist besser für uns Entwickler, wenn wir die Flexibilität haben, Änderungen leicht vorzunehmen. Zumindest sollten wir nicht mehr als eine Ebene von Kinderklassen haben.

Dekorateur-Muster

Mit einem Dekorateur können wir einem Objekt Eigenschaften hinzufügen, nachdem sie erstellt wurden. Dies bedeutet, dass wir Funktionalität hinzufügen können, ohne die Klasse unseres Objekts umzuwandeln. 

Anstatt zu denken, dass ein Kreis eine Form ist, könnten wir die Shape-Klasse verwenden, um Kreise zu erstellen und sie mit den zusätzlichen Eigenschaften zu versehen, die wir wünschen. Hier ist eine Alternative zum Erstellen von Kreisobjekten mit einem Dekorateur:

Klasse Shape Konstruktor (Daten) this.x = Daten.x; this.y = data.y;  getArea () … Funktion CircleDecorator (Form) Shape.radius = 3; shape.getArea = function () …; Form zurückkehren;  let shape = new Shape (x: 1, y: 2); let circle = new CircleDecorator (Form);

Wir können Mitglieder unserer Shape-Klasse mit einem Dekorateur hinzufügen oder ändern, anstatt ihn zu subklassifizieren. In unserem Beispiel für Shapes möchten Sie vielleicht, dass Sie ein Kreisobjekt erstellen möchten, das alle erforderlichen Eigenschaften hat und dasselbe für andere Shapes ausführen. Das ist gut. Mit einem Dekorateur können wir jedoch den Code in unserer Shape-Klasse wiederverwenden und ihn mit der Funktionalität ändern, die sich bei jeder Form unterscheidet. Als Ergebnis haben wir mehr Objekte, aber mehr Objekte sind einfacher zu verwalten als mehr Unterklassen.

Dieses Muster ist nicht auf das Erstellen von Grafiken beschränkt. Sie können es in jeder Situation verwenden, in der Sie einem Objekt Verantwortlichkeiten hinzufügen möchten. 

Beispielsweise verfügen wir möglicherweise über eine Klasse, die die Anmeldung von Benutzern bei unserem Konto übernimmt. Bevor wir ihre Informationen in unserer Datenbank speichern, ist es ratsam zu prüfen, ob die Eingabe gültig ist und keine schädlichen Skripts enthält. Wir könnten die Klasse mit einer Methode versehen, um die Informationen zuerst zu überprüfen. Derselbe Dekorateur kann überall in unserer Anwendung wiederverwendet werden, wo wir Benutzereingaben akzeptieren.

Zusammengesetztes Muster

Objekte können aus anderen Objekten bestehen. Die Ansicht einer App kann als eine Komponente betrachtet werden, die aus anderen Ansichten besteht. Wenn wir ein Spiel erstellen, zeigt unsere Spielwelt alle unsere Grafiken an, die wir wie Kreise und Quadrate erstellt haben. Jedes Mal, wenn wir unsere Ansicht aktualisieren, müssen wir jedes Element neu zeichnen. Wir brauchen eine Möglichkeit, alle Elemente als Gruppe zu verwalten. 

Hier kann uns das zusammengesetzte Muster helfen. Wir können eine Klasse erstellen, die für alle Elemente verantwortlich ist. Wenn wir die Elemente neu zeichnen möchten, rufen wir die draw-Methode dieser Klasse auf, und die draw-Methode wird für jedes einzelne Element aufgerufen.  

Klasse Komponente Konstruktor (Name) this.components = []; this.element = document.createElement (Name);  add (elem) this.components.push (elem);  draw () for (const elem of this.components) elem.draw ();  class Circle Konstruktor (Daten) this.x = data.x; this.y = data.y; this.radius = data.radius;  getArea () … draw () … let world = neue Komponente ('div'); Kreis = neuer Kreis (x: 1, y: 1, Radius: 2); sei kreis2 = neuer Kreis (x: 10, y: 10, Radius: 2); world.add (Kreis); world.add (circle2); world.draw ();

Eine Webseite kann auch als eine Komponente betrachtet werden. Diese Komponente kann ein Menü, eine Seitenleiste und einen Blogbeitrag enthalten. Der Beitrag wäre eine Unterkomponente mit einem Bild, einem Titel und einem Hauptteil. Das zeichnen Die Methode für unsere Haupt-App-Komponente ruft das Zeichnen in Menü, Seitenleiste und Post auf. Die Beitragskomponente ruft wiederum Zeichnen auf dem Beitragsbild, Titel und Text auf. 

Hier sehen Sie, was eine Webseite in Komponenten aufgeteilt haben möchte:

Dieses Muster ist nicht auf das Erstellen von Ansichten beschränkt. Wenn wir beispielsweise ein Spiel erstellen, verfügen wir möglicherweise über eine Komponente zum Verwalten der Elemente auf dem Bildschirm, eine Komponente zum Verwalten des Audios und eine Komponente zum Verwalten des Spielstatus. 

Diese würden sich alle in einer Komponente befinden, die ich die Game Engine nenne. Die Spiel-Engine hätte eine Initialisierungsmethode, die die Initialisierungsmethode für jede ihrer Unterkomponenten aufrufen würde. Das ist die Stärke bei der Verwendung des zusammengesetzten Musters. Anstatt sich mit einzelnen Objekten zu beschäftigen, können wir sie als ein Objekt behandeln.  

Fazit

Vererbung ermöglicht die Wiederverwendung von Code, indem ein Objekt in Bezug auf ein anderes Objekt definiert wird. Mit dem Dekorationsmuster können wir einem Objekt Zuständigkeiten hinzufügen, ohne den ursprünglichen Code oder die Unterklassifizierung zu ändern. Das zusammengesetzte Muster modelliert Teil-Ganzes-Beziehungen. Diese Muster sind nicht für die isolierte Verwendung gedacht. 

JavaScript ist die Sprache der Arbeit im Web geworden. Es ist nicht ohne Lernkurven, und es gibt viele Frameworks und Bibliotheken, um Sie zu beschäftigen. Wenn Sie nach zusätzlichen Ressourcen suchen, um zu studieren oder in Ihrer Arbeit zu verwenden, informieren Sie sich über das Angebot von Envato Market.

Sie können beliebig kombiniert werden. Die von mir bereitgestellten Beispiele sollten auch nicht als einzige Anwendung für die Verwendung der Muster verstanden werden. Sie sind nur eine Anleitung. Fühlen Sie sich frei, Ihre Kreativität einzusetzen, um sie anzuwenden. Es gibt keine Möglichkeit, sie oder einen Anwendungsfall zu implementieren.