JavaScript-ontwerppatronen deel 1: het fabriekspatroon

Foto door Patrick Hendry op Unsplash

De laatste tijd zijn de projecten waaraan ik heb kunnen werken in omvang toegenomen en heb ik de tijd genomen om dieper in te gaan op ontwerppatronen voor het schrijven van meer onderhoudbare en schaalbare JavaScript-code. Ontwerppatronen zijn een geweldige manier om tijd- en strijdgeteste oplossingen toe te passen op veel voorkomende problemen, zodat we ze sneller en efficiënter kunnen oplossen.

De meeste ontwerppatronen die we behandelen, zijn gebaseerd op Object Oriented Programming en als zodanig is het alleen maar logisch dat we beginnen met een kijkje te nemen in een creatief patroon dat zo wordt genoemd omdat het patroon ons een duidelijke interface biedt om objecten te creëren terwijl het wordt geabstraheerd de gevarieerde complexiteit of logica die betrokken is bij het maken ervan. Dit patroon wordt het fabriekspatroon genoemd en stelt ons in staat om eenvoudig objecten in JavaScript te maken.

Afkomstig van andere OOP, op klassen gebaseerde talen, zou men in de verleiding kunnen komen te denken dat wat we in de onderstaande coderegels gaan doen, klassen en instanties creëert, maar in werkelijkheid is dit gewoon syntactische suiker gemaakt om eruit te zien als syntaxis van een klasse gebaseerde taal.

Wat we in feite doen, is gebruik maken van de prototypische overerving van JavaScript en OLOO - Objecten koppelen aan andere objecten om objecten met een gedeeld prototype te maken. Het prototype zelf is gewoon een JavaScript-object en geen klasse in de ware zin van het woord. Een goede uitleg over overerving in Javascript en de verschillen met klassieke overerving is te vinden in het artikel van Eric Elliot hier.

Laten we wat code ingaan.

Alle voorbeelden uit deze serie zijn hier beschikbaar op Github en bevatten instructies voor het uitvoeren van de code.

Om de code in dit artikel uit te voeren, moet Node op uw computer zijn geïnstalleerd. Volg deze instructies als u deze nog niet hebt. Als u de repo volgt, vindt u instructies voor het uitvoeren van de code in de leesmij.

Laten we eerst een map maken. We kunnen het javascript-design-patronen in deze map noemen, we maken een fabrieksmap.

Het fabriekspatroon in actie

Het fabriekspatroon verpakt een constructor voor verschillende soorten objecten en retourneert instanties van de objecten via een eenvoudige API. Het maakt het gemakkelijk om verschillende objecten te maken door een eenvoudige API bloot te leggen die het opgegeven objecttype retourneert.

Laten we beginnen met het maken van onze constructeurs. Deze functies zijn verantwoordelijk voor het retourneren van nieuwe objecten van een specifiek type wanneer ze worden aangeroepen.

Laten we in de fabrieksmap een laptop.js-bestand maken.

const Laptop = functie ({ram, hdd, name}) {
  this.ram = ram || 0;
  this.hdd = hdd || 0;
  this.name = naam || "";
};
module.exports = Laptop;

In dit bestand maken we een laptopconstructorfunctie. Het accepteert een object als parameter met attributen voor het instantiëren van het object met verschillende specificaties die we willen vastleggen - in dit geval RAM-geheugen, HDD-grootte en een apparaatnaam.

Daarna exporteren we de Laptop-constructorfunctie vanuit de module.

Laten we een ander bestand maken met de naam tablet.js

We doen hetzelfde, maar met specificaties die relevanter zijn voor een tablet.

const Tablet = functie ({ram, hdd, naam, netwerk}) {
    this.ram = ram || 0;
    this.hdd = hdd || 0;
    this.network = netwerk || 0;
    this.name = naam || "";
};
module.exports = Tablet;

Nu we onze constructeurs hebben, laten we de fabrieksfunctie maken waarmee de API wordt weergegeven voor het maken van nieuwe exemplaren van deze items. Voeg een nieuw bestand toe met de naam gadgetFactory.js

const Laptop = vereisen ("./ laptop");
const Tablet = vereisen ("./ tablet");
const gadget = {Laptop, Tablet};
module.exports = {
    createGadget (type, attributen) {
        const GadgetType = gadget [type];
        retourneer nieuw GadgetType (attributen);
    }
};

Hier beginnen we met het importeren van de constructors voor het maken van laptop- en tabletobjecten. We maken vervolgens een gadgetobject met de constructornamen als sleutels. Dit maakt het mogelijk voor ons om toegang te krijgen tot het type constructor dat we willen gebruiken met behulp van gadget [type] - waar in dit voorbeeld het type "Laptop" of "Tablet" zal zijn. Ten slotte exporteren we een object uit deze module met een createGadget-methode. Deze methode accepteert een gadgettype als de eerste parameter en roept het opgegeven constructortype aan terwijl de attributen eraan worden doorgegeven.

Merk op dat wanneer we een functie aanroepen met het nieuwe trefwoord in Javascript, we een leeg object terugkrijgen met een set van deze binding aan die in de uitvoerende functie. Deze unieke aanroep creëert ook een prototypische relatie tussen de constructorfunctie en nieuwe objecten die we op deze manier maken. We zullen dit in detail zien in de andere ontwerppatronen die we zullen behandelen.

Ook vermeldenswaardig is dat de hoofdletter alleen een conventie is en geen vereiste. Het doet niets bijzonders en we hadden net zo goed de functies met camelCase kunnen noemen, zoals we gewoonlijk doen met andere variabele- en functienamen in JavaScript.

Op dit punt kunnen we nu het bestand maken dat gebruik maakt van (of verbruikt) onze fabriekspatroon-API.

Maak een index.js-bestand en voeg de volgende code toe.

const gadgetFactory = vereisen ("./ gadgetFactory");
const myLaptop = gadgetFactory.createGadget ("Laptop", {
    ram: 8,
    ssd: 256,
    naam: "Bab's MacBook Pro"
});
const myTablet = gadgetFactory.createGadget ("Tablet", {
    ram: 4,
    hdd: 128,
    naam: "Bab's iPad",
    netwerk: '4G'
});
console.log (myLaptop);
console.log (myTablet);

Het eerste dat u misschien opvalt, is dat we in dit bestand de constructeurs voor laptops en tablets niet rechtstreeks nodig hebben. Het enige dat we nodig hebben, is de gadgetFactory-module (met de createGadget-methode). Met behulp van deze methode maken we vervolgens twee exemplaren van respectievelijk een laptop en tablet en loggen ze uit bij de console.

Navigeer nu in uw terminal naar de map javascript-design-patterns en typ:

$ node ./factory/index.js

U zou het volgende moeten zien aangemeld bij de console:

Laptop {ram: 8, ssd: 256, naam: 'Bab \' s MacBook Pro '}
Tablet {ram: 4, hdd: 128, netwerk: '4G', naam: 'Bab \' s iPad '}

Zoals u kunt zien, hebben we één laptop-objecttype en een tablettype gemaakt, elk met hun eigen specificaties. Met dit patroon kunt u zoveel gadgetobjecten maken als u wilt, elk met hun eigen specificaties.

En dat is het voor het fabriekspatroon. Dit is natuurlijk een nogal simplistische implementatie, en in iets anders dan een triviale app zou je zeker strengere logica willen opnemen, bijvoorbeeld rond je constructeurs.

In dit voorbeeld hebben we de constructorfuncties van Javascript gebruikt, maar dit patroon kan ook worden geïmplementeerd met behulp van prototypes. We zullen dit in een volgend artikel onderzoeken wanneer we onze code wijzigen om deze efficiënter te maken.

Verderop in de serie behandelen we het populaire patroon van uitgever / abonnee (of PubSub in het kort). Om me op de hoogte te houden, moet je me een follow geven en als je dit artikel nuttig vond, laat dan een duim omhoog (of 5 ). Zoals altijd hoor ik graag je mening in de reacties hieronder!

Update: Deel 2 van de serie over het patroon Publisher / Subscriber vindt u hier.

Babs is een JavaScript-ontwikkelaar die meestal React / React Native & NodeJS (met een gezonde dosis GraphQL) overdag schrijft en al het andere JavaScript onder de dekking van de nacht. Je kunt hem vinden op Twitter en Instagram waar hij details van zijn clandestiene liefdesaffaire deelt met JavaScript.