JavaScript-designmønstre Del 1: Fabriksmønsteret

Foto af Patrick Hendry på Unsplash

På det seneste, efterhånden som de projekter, jeg har haft muligheden for at arbejde på, er vokset i omfang, har jeg taget mig tid til at gå dybere ned i designmønstre til at skrive en mere vedligeholdelig og skalerbar Javascript-kode. Designmønstre er en fantastisk måde at anvende tids- og kamptestede løsninger på almindelige problemer, så vi hurtigere og mere effektivt kan løse dem.

De fleste af de designmønstre, vi dækker, er baseret på objektorienteret programmering, og som sådan giver det kun mening, at vi begynder med at se på et kreativt mønster, såkaldt, fordi mønsteret giver os en klar grænseflade til at skabe objekter, mens vi abstraherer væk den varierede kompleksitet eller logik, der er forbundet med at skabe dem. Dette mønster kaldes fabriksmønsteret og det giver os mulighed for nemt at oprette objekter i JavaScript.

Kommer fra andre OOP, klassebaserede sprog, kan man blive fristet til at tro, at det, vi laver i kodelinjerne nedenfor, er at skabe klasser og tilfælde, men i virkeligheden er dette bare syntaktisk sukker, der ligner syntaks fra en klasse baseret sprog.

Det, vi faktisk gør, er at udnytte JavaScript's prototype arv og OLOO - Objekter, der linker til andre objekter for at oprette objekter med en delt prototype. Prototypen i sig selv er bare et almindeligt JavaScript-objekt og ikke en klasse i ordets sande forstand. En stor forklaring på arv i Javascript og det er forskelle fra klassisk arv findes i Eric Elliot's artikel her.

Lad os dykke ned i nogle kode.

Alle eksempler fra denne serie vil være tilgængelige på Github her og inkluderer instruktioner til, hvordan du kører koden.

For at køre koden i denne artikel skal du have Node installeret på din maskine. Følg disse instruktioner, hvis du ikke allerede har den. Hvis du følger med på repoen, finder du instruktioner til at køre koden i readme.

Første ting først, lad os oprette en mappe. Vi kan kalde det javascript-design-mønstre i denne mappe, vi opretter en fabriksmappe.

Fabriksmønsteret i aktion

Fabriksmønsteret indpakker en konstruktør til forskellige typer objekter og returnerer forekomster af objekter via et simpelt API. Det gør det nemt at oprette forskellige objekter ved at udsætte et simpelt API, der returnerer den specificerede objekttype.

Lad os starte med at oprette vores konstruktører. Disse funktioner er ansvarlige for returnering af nye objekter af en bestemt type, når de kaldes op.

Lad os oprette en laptop.js-fil i fabriksmappen.

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

I denne fil opretter vi en Laptop-konstruktorfunktion. Det accepterer et objekt som en parameter med attributter til at instantisere objektet med forskellige specifikationer, som vi ønsker at indfange - i dette tilfælde RAM-størrelse, HDD-størrelse og et enhedsnavn.

Derefter eksporterer vi funktionen Laptop-konstruktør fra modulet.

Lad os oprette en anden fil kaldet tablet.js

Vi gør det samme, men med specifikationer, der er mere relevante for en tablet.

const Tablet = funktion ({ram, hdd, navn, netværk}) {
    dette.ram = ram || 0;
    dette.hdd = hdd || 0;
    this.network = netværk || 0;
    this.name = name || "";
};
module.exports = Tablet;

Nu hvor vi har vores konstruktører, så lad os oprette den fabriksfunktion, der afslører API'en til at oprette nye forekomster af disse elementer. Tilføj en ny fil kaldet gadgetFactory.js

const Laptop = kræver ("./ laptop");
const Tablet = kræver ("./ tablet");
const gadget = {Laptop, tablet};
module.exports = {
    createGadget (type, attributter) {
        const GadgetType = gadget [type];
        returner ny GadgetType (attributter);
    }
};

Her starter vi med at importere konstruktører til oprettelse af bærbare og tablet-objekter. Vi opretter derefter et gadget-objekt ved hjælp af konstruktørens navne som nøgler. Dette gør det muligt for os at få adgang til den type konstruktør, vi ønsker, ved hjælp af gadget [type] - hvor typen i dette eksempel enten er "Laptop" eller "Tablet". Endelig eksporterer vi et objekt fra dette modul med en createGadget-metode. Denne metode accepterer en gadgetype som den første parameter og kalder den angivne konstruktortype, mens de indtaster attributterne til den.

Du skal bemærke, at når vi kalder en funktion med det nye nøgleord i Javascript, får vi til gengæld et tomt objekt med et dette bindende sæt til det i eksekveringsfunktionen. Dette unikke opkald skaber også et prototype forhold mellem konstruktørfunktionen og eventuelle nye objekter, vi skaber på denne måde. Vi ser dette detaljeret i de andre designmønstre, vi vil dække.

Det er også værd at bemærke, at hovedbogstavet kun er en konvention og ikke et krav. Det gør ikke noget specielt, og vi kunne lige så godt have navngivet funktionerne med camelCase, som vi normalt gør med andre variabel- og funktionsnavne i JavaScript.

På dette tidspunkt kan vi nu oprette den fil, der vil bruge (eller forbruge) vores fabriksmønster API.

Opret en index.js-fil, og tilføj følgende kode.

const gadgetFactory = kræve ("./ gadgetFactory");
const myL laptop = gadgetFactory.createGadget ("Laptop", {
    ram: 8,
    ssd: 256,
    navn: "Bab's MacBook Pro"
});
const myTablet = gadgetFactory.createGadget ("Tablet", {
    ram: 4,
    hdd: 128,
    navn: "Bab's iPad",
    netværk: '4G'
});
console.log (myLaptop);
console.log (myTablet);

Den første ting du måske bemærker er, at i denne fil behøver vi ikke konstruktører til bærbare computere og tabletter direkte. Alt, hvad vi har brug for, er gadgetFactory-modulet (med det er createGadget-metoden). Ved hjælp af denne metode opretter vi derefter to tilfælde af henholdsvis en bærbar computer og tablet og logger dem ud på konsollen.

Naviger nu i din terminal til mappen javascript-design-mønstre og skriv:

$ node ./factory/index.js

Du skal se følgende logget på konsollen:

Bærbar computer {ram: 8, ssd: 256, navn: 'Bab \' s MacBook Pro '}
Tablet {ram: 4, hdd: 128, netværk: '4G', navn: 'Bab \' s iPad '}

Som du kan se, oprettede vi en bærbar objekttype såvel som en tablet-type, hver med deres egne specifikationer. Ved hjælp af dette mønster kan du oprette så mange gadgetobjekter, som du har brug for hver med deres egne specifikationer.

Og det er det for fabriksmønsteret. Dette er selvfølgelig en temmelig forenklet implementering, og i noget andet end en triviel app vil du bestemt gerne have en mere streng logik - f.eks. Omkring dine konstruktører.

I dette eksempel brugte vi Javascript's konstruktorfunktioner, men dette mønster kan også implementeres ved hjælp af prototyper. Vi vil undersøge dette i en efterfølgende artikel, når vi refaktorerer vores kode for at gøre den mere effektiv.

Næste gang i serien dækker vi det populære udgiver / abonnentmønster (eller PubSub kort). For at holde besked skal du sørge for at følge mig, og hvis du synes, at denne artikel er nyttig, skal du lade tommelfingeren op (eller 5 ). Som altid ville jeg meget gerne høre dine tanker i kommentarerne herunder!

Opdatering: Du kan finde del 2 af serien, der dækker udgiver / abonnentmønsteret her.

Babs er en JavaScript-udvikler, der for det meste skriver React / React Native & NodeJS (med en sund dosis GraphQL) om dagen og alt andet JavaScript under dækning af natten. Du kan finde ham på Twitter og Instagram, hvor han deler detaljer om sin hemmelige kærlighedsaffære med JavaScript.