Overerving en uitbreiding van objecten met JavaScript

Als u bekend bent met objectgeoriënteerd programmeren, bent u waarschijnlijk bekend met subclassificatie en overerving. De erfenis heeft echter een slechte rap gekregen. Ik denk dat dit komt omdat sommige ontwikkelaars het als een alles omvattende oplossing zien wanneer je een programma moet wijzigen. Het probleem hiermee is dat klassehiërarchieën onhandelbaar kunnen worden. 

Er zijn andere ontwerppatronen die we kunnen gebruiken om onze apps begrijpelijker en klaar voor verandering te maken. Ik zal u voorbeelden tonen van hoe u overerving en de decorateur en het samengestelde patroon kunt gebruiken om het ontwerp van uw programma te verbeteren.

Erfenis

Het idee achter successie is dat één object "een" gespecialiseerde versie van een ander object is. Er is een bovenliggende klasse (ook bekend als een superklasse) die de basiseigenschappen van ons object definieert. En er is een onderliggende klasse (subklasse) die de eigenschappen van de bovenliggende klasse overneemt. 

Een voorbeeld van overerving is een hond en een poedel. Alle honden hebben bepaalde kenmerken, zoals vier poten en het vermogen om te blaffen. Een poedel "is een" soort hond. Een SUV is een voertuig. Een cirkel is een vorm. Dit is hoe onze klassenhiërarchie eruit zou zien als we een programma zouden ontwerpen voor het maken van vormen.

Het voordeel van het hebben van een klasse Shape is dat we de eigenschappen en methoden die we in andere klassen hebben gedefinieerd, opnieuw kunnen gebruiken. 

Merk op dat de getArea methode is opnieuw gedefinieerd in elk van onze subklassen. We hoefden deze methode niet opnieuw te definiëren, maar we deden het om de implementatie door onze ouder van de methode te vervangen. Dat komt omdat elke vorm zijn eigen manier heeft om het gebied te berekenen. 

Het overschrijven van een bovenliggende methode in een onderliggende klasse is een voorbeeld van polymorfisme. Polymorfisme is het vermogen van objecten om meerdere vormen te hebben. Hiermee kunnen subklassen methoden hebben met dezelfde naam als hun superklasse maar met verschillende implementaties.  

Dit is een voorbeeld van hoe onze code eruit zou zien voor het maken van een Shape en Circle-subklasse:

class Shape constructor (x, y) this.xPosition = x; this.yPosition = y;  getArea () ... klasse Circle breidt Shape uit constructor (x, y, radius) super (x, y, radius); this.radius = radius getArea () ... let circle = new Circle (1,2,3);

Een van de nadelen van deze ontwerpkeuze is dat als u besluit dat de bovenliggende klasse moet worden gewijzigd, de subklassen mogelijk ook moeten worden gewijzigd, samen met alle objecten die we hebben gemaakt. 

Stel dat we later hebben besloten dat het beter zou zijn om de x- en y-parameters van de Shape-klasse te vervangen door een object. Daarom moeten we de constructor voor al onze subklassen en de argumenten voor elk object wijzigen dat we hebben geïnstantieerd.

We kunnen zien hoe dit gemakkelijk problematisch kan worden. We zouden ervoor moeten zorgen dat we ons ontwerp de eerste keer goedkeuren, zodat we een verandering niet kunnen voorkomen. Maar dat is niet praktisch en ook niet waar we naar moeten streven. Een programma is een steeds evoluerende entiteit en het is beter voor ons ontwikkelaars als we de flexibiliteit hebben om gemakkelijk wijzigingen aan te brengen. Op zijn minst zouden we niet meer dan één niveau van kinderlessen moeten hebben.

Decorator patroon

Met een binnenhuisarchitect kunnen we eigenschappen aan een object koppelen nadat ze zijn gemaakt. Dit betekent dat we functionaliteit kunnen toevoegen zonder te subclasseren of bezorgd zijn over de implementatie van ons object. 

In plaats van te denken dat een cirkel een vorm is, kunnen we de klasse Shape gebruiken om cirkels te maken en deze om te slaan met de extra eigenschappen die we willen. Hier is een alternatief voor het maken van cirkelobjecten met een decorateur:

class Shape constructor (data) this.x = data.x; this.y = data.y;  getArea () ... functie CircleDecorator (vorm) shape.radius = 3; shape.getArea = function () ...; vorm teruggeven;  let shape = new Shape (x: 1, y: 2); laat cirkel = nieuwe CircleDecorator (vorm);

We kunnen leden van onze Shape-klasse toevoegen of wijzigen met een decorateur in plaats van deze te subclasseren. In ons voorbeeld met vormen ziet u misschien dat u gewoon een cirkelobject wilt maken met alle eigenschappen die u nodig hebt en hetzelfde wilt doen voor andere vormen. Dat is prima. Maar een decorateur stelt ons in staat de code opnieuw te gebruiken in onze Shape-klasse en deze te wijzigen met de functionaliteit die verschilt per vorm. Als gevolg hiervan zullen we meer objecten hebben, maar meer objecten zijn gemakkelijker te beheren dan meer subklassen.

Dit patroon is niet beperkt tot het maken van afbeeldingen. U kunt het gebruiken in elke situatie waarin u verantwoordelijkheden aan een object wilt toevoegen. 

We hebben bijvoorbeeld een klasse die gebruikers aanmeldt bij onze account. Voordat we hun informatie in onze database opslaan, is het verstandig om te controleren of de invoer geldig is en geen schadelijke scripts bevat. We zouden de klas kunnen versieren met een methode om de informatie eerst te valideren. Deze zelfde decorateur kan overal in onze applicatie worden hergebruikt, waar we gebruikersinvoer accepteren.

Samengesteld patroon

Objecten kunnen zijn samengesteld uit andere objecten. De weergave voor een app kan worden beschouwd als een component die is samengesteld uit andere weergaven. Als we een spel zouden maken, zou onze gamewereld al onze afbeeldingen weergeven die we als cirkels en vierkanten hebben gemaakt. Telkens wanneer we onze weergave bijwerken, moeten we elk element opnieuw tekenen. We hebben een manier nodig om alle elementen als een groep te beheren. 

Dat is waar het samengestelde patroon ons kan helpen. We kunnen een klasse maken die verantwoordelijk is voor alle elementen. Wanneer we de elementen opnieuw willen tekenen, noemen we de tekenmethode van deze klasse en wordt de tekenmethode voor elk afzonderlijk element aangeroepen.  

klasse Component constructor (naam) this.components = []; this.element = document.createElement (naam);  add (elem) this.components.push (elem);  draw () for (const elem of this.components) elem.draw ();  class Circle constructor (data) this.x = data.x; this.y = data.y; this.radius = data.radius;  getArea () ... draw () ... let world = new Component ('div'); laat cirkel = nieuwe cirkel (x: 1, y: 1, straal: 2); laat circle2 = new Circle (x: 10, y: 10, radius: 2); world.add (cirkel); world.add (circle2); world.draw ();

Een webpagina kan ook als een component worden beschouwd. Dit onderdeel kan een menu, een zijbalk en een blogbericht bevatten. De post zou een subcomponent zijn met een afbeelding, een titel en een hoofdtekst. De trek methode voor onze belangrijkste app-component zal draw op het menu, zijbalk en post roepen. De postcomponent roept op zijn beurt tekening op de afbeelding, titel en tekst van het bericht. 

Hier is een weergave van wat een webpagina zou willen, onderverdeeld in componenten:

Dit patroon is niet beperkt tot het maken van weergaven. Als we bijvoorbeeld een game maken, hebben we mogelijk een component om de elementen op het scherm te beheren, een component om de audio te beheren en een component om de spelstatus te beheren.. 

Deze zouden allemaal in een component zitten die ik de game-engine noem. De game-engine zou een initialiseermethode hebben die de initialisatiemethode zou aanroepen op elk van zijn subcomponenten. Dat is de kracht van het gebruik van het composietpatroon. In plaats van individuele objecten te behandelen, kunnen we ze als één object behandelen.  

Conclusie

Met overerving kunnen we code opnieuw gebruiken door een object te definiëren in termen van een ander object. Het patroon van de decorateur stelt ons in staat om verantwoordelijkheden aan een object toe te voegen zonder de originele code of subclassering te veranderen. Het samengestelde patroon modelleert gedeeltelijke relaties. Deze patronen zijn niet bedoeld om geïsoleerd te worden gebruikt. 

JavaScript is de taal geworden van werken op internet. Het is niet zonder zijn leercurven, en er zijn ook genoeg kaders en bibliotheken om je bezig te houden. Als u op zoek bent naar extra middelen om te studeren of om te gebruiken in uw werk, kijk dan wat we op Envato Market beschikbaar hebben.

Ze kunnen naar eigen inzicht worden gecombineerd. De voorbeelden die ik heb verstrekt, moeten ook niet worden beschouwd als de enige toepassing voor het gebruik van de patronen. Ze zijn slechts een gids. Voel je vrij om je creativiteit te gebruiken om ze toe te passen. Er is geen manier om ze uit te voeren of één use-case.