Een ontwerppatroon is een sjabloon dat een veel voorkomend probleem bij het ontwerpen van software oplost.
Het waarnemerspatroon, ook wel bekend als het publish-subscribe-patroon, is een gedragspatroon. Hiermee kunt u meerdere objecten of abonnees op de hoogte stellen van elke gebeurtenis die is gepubliceerd in het object dat ze observeren.
Hier leert u hoe u het ontwerppatroon van de waarnemer in TypeScript implementeert.
Het waarnemerspatroon
Het waarnemerspatroon werkt door een een-op-veel-relatie te definiëren tussen de uitgever en zijn abonnees. Wanneer een evenement plaatsvindt in de uitgever, worden alle abonnees op dat evenement op de hoogte gebracht. Een wijdverspreid voorbeeld van dit patroon is JavaScript-gebeurtenislisteners.
Neem voor de context aan dat u een inventaristracker aan het bouwen bent die het aantal producten in uw winkel bijhoudt. In dit geval is uw winkel het onderwerp/de uitgever en uw voorraad de waarnemer/abonnee. Het gebruik van het ontwerppatroon van de waarnemer zou in deze situatie optimaal zijn.
In het ontwerppatroon van de waarnemer moet uw onderwerpklasse drie methoden implementeren:
- Een bijvoegen methode. Deze methode voegt een waarnemer toe aan het onderwerp.
- A losmaken methode. Deze methode verwijdert een waarnemer van een onderwerp.
- A melden/bijwerken methode. Deze methode waarschuwt de waarnemers van het onderwerp wanneer de toestand van het onderwerp verandert.
Uw waarnemersklasse moet één methode implementeren, de update methode. Deze methode reageert wanneer er een verandering is in de toestand van het onderwerp.
Implementatie van de onderwerp- en waarnemerklassen
De eerste stap bij het implementeren van dit patroon is het maken van interfaces voor de subject- en waarnemerklasse, om ervoor te zorgen dat ze de juiste methoden implementeren:
// Onderwerp/uitgever-interface
koppelOnderwerp{
attachObserver (waarnemer: Observer): leegte;
detachObserver (waarnemer: Observer): leegte;
waarnemer op de hoogte brengen(): leegte;
}
// Observer/abonnee-interface
koppelWaarnemer{
update(onderwerp: onderwerp): leegte;
}
De interfaces in het bovenstaande codeblok definiëren de methoden die uw concrete klassen moeten implementeren.
Een concrete vakklasse
De volgende stap is het implementeren van een concrete onderwerpklasse die de Onderwerp koppel:
// Onderwerp
klasWinkelimplementeertOnderwerp{}
Initialiseer vervolgens de Onderwerpstaat in de Winkel klas. De waarnemers van het onderwerp zullen reageren op veranderingen in deze toestand.
In dit geval is de toestand een getal en zullen de waarnemers reageren op een toename van het aantal:
// Onderwerpstatus
privaat numberOfProducts: aantal;
Initialiseer vervolgens een reeks waarnemers. Met deze array houdt u de waarnemers bij:
// Waarnemers initialiseren
privaat waarnemers: Waarnemer[] = [];
Mogelijk vindt u enkele implementaties van het waarnemerspatroon met behulp van a Stel de gegevensstructuur in in plaats van een array om de waarnemer bij te houden. Het gebruik van een set zorgt ervoor dat dezelfde waarnemer niet twee keer verschijnt. Als u in plaats daarvan een array wilt gebruiken, moet u controleren op dubbele waarnemers in uw bijvoegen methode.
Vervolgens moet u de Onderwerp's methoden—bijvoegen, losmaken, En melden/bijwerken- in je concrete klas.
Implementeren van de bijvoegen methode, controleer eerst of de waarnemer al is aangesloten en geef een foutmelding als dit het geval is. Voeg anders de waarnemer toe aan de array met behulp van de JavaScript-array-methode, duw:
// Waarnemer(s) bevestigen
attachObserver (waarnemer: Observer): leegte {
// Controleer of de waarnemer al is bevestigd
const waarnemerBestaat = dit.observers.includes (waarnemer);als (waarnemerBestaat) {
gooiennieuwFout('Observer is al geabonneerd');
}
// Voeg een nieuwe waarnemer toe
dit.waarnemers.duw(waarnemer);
}
Implementeer vervolgens uw losmaken methode door de index te vinden en deze uit de array te verwijderen met behulp van JavaScript splitsen methode.
Er kunnen scenario's zijn waarbij de waarnemer die u probeert los te koppelen al is losgekoppeld of in de eerste plaats niet was aangemeld. U moet deze scenario's afhandelen door een voorwaardelijke instructie toe te voegen om te controleren of de waarnemer zich in de array of de set bevindt, al naargelang het geval.
// Waarnemer(s) loskoppelen
detachObserver (waarnemer: Observer): leegte {
troosten.log('Afnemende waarnemer ${JSON.stringify (waarnemer)}`);
const waarnemerIndex = dit.waarnemers.indexOf (waarnemer);als (observerIndex -1) {
gooiennieuwFout('Waarnemer bestaat niet');
}
dit.waarnemers.splitsing(waarnemerIndex, 1);
console.log('Waarnemer losgekoppeld...');
}
Implementeer vervolgens uw melden/bijwerken methode door uw lijst met waarnemers te doorlopen en de update methode van elk:
// Kennisgeving van waarnemers
waarnemer op de hoogte brengen(): leegte {
console.log('Waarnemers informeren...');
voor (const waarnemer vandit.waarnemers) {
waarnemer.update(dit);
}
}
Tot slot voor de Onderwerp class, een methode implementeren die de staat manipuleert en vervolgens de waarnemers op de hoogte stelt van de verandering door hun melden/bijwerken methode. Dit voorbeeld is een vereenvoudiging van hoe een proefpersoon een actie kan uitvoeren en vervolgens waarnemers kan informeren:
// Status wijzigen en waarnemers op de hoogte stellen
nieuwProduct (producten: aantal): leegte {
dit.numberOfProducts += producten;
console.log('Nieuw product toegevoegd aan de winkel');
dit.notifyObserver();
}
Concrete waarnemersklassen
Maak een waarnemersklasse of klassen om u te abonneren op de uitgever. Elke waarnemersklasse moet de Waarnemer koppel.
De waarnemersklassen zullen een melden/bijwerken methode die alleen het onderwerp dat ze observeren mag aanroepen. Deze methode moet alle bedrijfslogica bevatten die u nodig hebt om te reageren op een verandering in de status van het onderwerp:
// Betonwaarnemer 1
klasInventarisimplementeertWaarnemer{
update(): leegte {
console.log('Nieuw product toegevoegd aan de winkel, voorraad bijwerken...');
// Daadwerkelijke bedrijfslogica komt hier...
}
}
// Betonwaarnemer 2
klasKlantimplementeertWaarnemer{
update(): leegte {
console.log('Nieuw product toegevoegd aan de winkel, ik moet het gaan bekijken...');
// Daadwerkelijke bedrijfslogica komt hier...
}
}
Het waarnemerspatroon gebruiken
Om dit patroon te gebruiken, moet u de concrete subject- en waarnemerklassen instantiëren. Zodra je dit hebt gedaan, bel je het onderwerp bijvoegen methode en geef de instantie Observer door als argument. Als reactie hierop zal de proefpersoon die instantie toevoegen aan zijn lijst met waarnemers:
// Instantiëren van onderwerp en waarnemer
const winkel = nieuw Winkel();
const inventaris = nieuw Inventaris();
const klant = nieuw Klant()
// Objecten abonneren op uitgever
winkel.attachObserver(inventaris);
winkel.attachObserver(klant);
// Onderwerpstatus wijzigen
winkel.nieuw product(30);
Deze code simuleert een toestandsverandering. De wijziging activeert de meldingsmethode op de Onderwerp klas. Deze methode roept op zijn beurt de melden methode op elk van zijn waarnemers. Elke waarnemer voert dan zijn eigen bedrijfslogica uit.
U moet dit patroon alleen gebruiken wanneer de wijzigingen in de toestand van een object van invloed zijn op andere objecten en de set objecten in kwestie onbekend of dynamisch is.
Voordelen van het gebruik van het waarnemerspatroon
Door dit patroon in uw code te gebruiken, kunt u het open/close-principe handhaven. U kunt zoveel abonnees toevoegen als u wilt en tijdens runtime relaties tussen objecten tot stand brengen, zonder de code van het onderwerp te wijzigen.