Designmønstre - En rask guide til observatørmønster.

Observatormønster er et veldig ofte brukt mønster. Det er faktisk så vanlig at det blir standardisert i mange programmeringsspråk / biblioteker. I Java eksisterer den injava.util.Observer (avskrevet i Java 9). I Python er det så nær som apip install mønster-observatør. I C ++ kan vi noen ganger bruke boost-bibliotek, mer presist #include . Imidlertid er det mye brukt i industrien som en skreddersydd løsning. For å kunne bruke den riktig og forstå dens kompleksitet, må vi dykke inn og utforske den.

Observatormønster er klassifisert blant atferdsmønsteret. Atferdsdesignmønstre er mest spesifikt opptatt av kommunikasjon mellom klasser / objekter. [av Design Patterns forklart ganske enkelt]

Hva er et observatørmønster? Bortsett fra en gåmonitor som kringkaster analog TV (som på bildet). Mønsterets mål er å definere en en-til-mange-relasjon slik at når ett objekt endrer tilstand, blir de andre varslet og oppdatert automatisk. Mer presist ønsker den å bli informert om hendelser som skjer i systemet. La oss sette brikkene i puslespillet sammen i tre trinn.

Trinn 1 - Stikkord

Å definere nøkkelord er den hemmelige oppskriften i denne serien med hurtigguider. Denne metoden hjalp meg virkelig å forstå designmønstrene, hardkode dem i tankene mine og forstå forskjellene mellom andre designmønstre.

  1. Emne: Det anses som innehaveren av informasjon, data eller forretningslogikk.
  2. Registrer / legg ved: Observatører registrerer seg selv til emnet fordi de ønsker å bli varslet når det skjer en endring.
  3. Hendelse: Hendelser fungerer som en trigger i emnet slik at alle observatører blir varslet.
  4. Varsle: Avhengig av implementering, kan emnet "skyve" informasjon til observatørene, eller kan observatørene "trekke" hvis de trenger informasjon fra emnet.
  5. Oppdatering: Observatører oppdaterer staten uavhengig av andre observatører, men deres tilstand kan endres avhengig av den utløste hendelsen.

Trinn 2 - Diagram

Kan dele dette designet i forskjellige klasser for å forenkle dette litt.

  • ConcreteObservers er klasser som inneholder informasjon som er spesifikk for den aktuelle forekomsten. Oppdateringsfunksjonen blir kalt av fagets varsling () -operasjon. Observatørene oppdaterer uavhengig basert på deres nåværende tilstand.
  • Observatøren er foreldreklassen til de konkrete observatørene. Den inneholder en fagforekomst. Når en observatør initialiseres, registrerer / knytter den seg til motivet.
  • Emneklassen har en liste eller en samling observatører. Når en hendelse utløses, ringer den varslingsoperasjonen () som sløyfer gjennom alle observatører ved å kalle oppdateringsfunksjonen.

Trinn 3 - Kode etter eksempel

Jeg vil foreslå å kopiere kodeklassen for klasse fra git-depotet “Andreas Poyias” eller tekstutdragene nedenfor (i den angitte rekkefølgen) og lime den inn i en av de tilgjengelige online C ++ -redigeringsprogrammer som c ++ shell, jdoodle, onlineGDB og kjøre det for å observere utgangen. Les deretter kommentarene eller beskrivelsen nedenfor. Ta deg god tid og les den grundig (det betyr ett minutt, ikke mindre og ikke mer).

Eksempel: Tenk på en fotballkamp. Mange supportere ser på spillet. Vi delte supporterne i to kategorier etter alder, unge og gamle. Når laget deres scorer et mål, reagerer supporterne annerledes etter alder og spenningsnivå.
La oss snakke med ord som brukes for observatørmønsteret:

  • Spillet er temaet og supporterne er observatørene.
  • Alle observatører er knyttet / registrert til emnet, og de blir varslet når fotballaget deres scorer (trigger-hendelsen er hvis laget deres scorer).
  • Observatørene oppdaterer sin oppførsel avhengig av mottatt varsel.

Emne
For denne klassen trenger vi tilgang til en liste over observatører. Når observatørene er i ferd med å registrere seg, kaller de theattach (denne) -funksjonen for å legge seg til den tilgjengelige listen (dette er en observatørs eksempel). Når en hendelse utløses, wenotify () alle observatørene for å uavhengig oppdatere sin tilstand. I dette eksemplet er utløseren hvis observatørens fotballag scoret.

# inkluder 
#include 
bruker navneområde std;
klasseemne {
    vektor  observatører;
    bool scoret; // trigger, hendelse
offentlig:
    // registrere observatører
    void attach (Observer * obs) {
        observers.push_back (obs);
    }
   
   // Dette er EVENT
   // angi hvis scoret og varsle ALLE observatører
   void setScored (bool Score) {
      scoret = Score;
      gi beskjed();
   }
bool getScored () {
      retur scoret;
   }
   // varsle implementering er lenger nede
   // slik at skriptet kompilerer og kjøres
   ugyldig varsling ();
};

Observer
Denne klassen er avhengig av emnet den er registrert med. Når konkrete observatører initialiseres, knytter de seg til prosjektet. I dette eksemplet er tilstanden til hver observatør hans spenning. Utviklingen i spillet.

klasse observatør
{
    Emne * subj;
    int spenning Nivå; // stat
  offentlig:
    Observer (Subject * mod, int excLevel)
    {
        subj = mod;
        spenningsnivå = excLevel;
        // Observatører registrerer / knytter seg til emnet
        subj-> fester (this);
    }
    virtual void update () = 0;
  beskyttet:
    Emne * getSubject () {
       returnere subj;
    }
    void setExcitationLevel (int excLevel) {
       spenningsnivå = excLevel;
    }
    int getExcitationLevel () {
       returnere spenning;
    }
};

Dette er theSubject :: notify () -erklæringen, og som vi nevnte før jobben er å varsle alle observatører om å oppdatere sin tilstand.

void Subject :: varsle () {
  for (int i = 0; i  oppdatering ();
}

Betongobservatører
Betongobservatørene arver fra Observer-klassen, og de må alle ha oppdateringsfunksjonen. I dette eksemplet skilles de konkrete observatørene mellom unge og gamle støttespillere. Hvis spenningsnivået deres blir for høyt, har de eldre supporterne risikoen for hjerteinfarkt, og de yngre har risikoen for å drikke og kjøre bil. Deres tilstand oppdateres uavhengig som vi vil bevise i hovedfunksjonen lenger nedenfor.

klasse Old_ConcreteObserver: public Observer
{
   offentlig:
     // Ringer foreldrekonstruktør til å registrere seg med emne
     Old_ConcreteObserver (Subject * mod, int div)
        : Observer (mod, div) {}
     // For eldre mennesker, hvis spenningsnivået
     // er over 150 risikoen for hjerteinfarkt
     ugyldig oppdatering ()
     {
        bool scoret = getSubject () -> getScored ();
        setExcitationLevel (getExcitationLevel () + 1);
        if (scoret && getExcitationLevel ()> 150)
        {
          cout << "Old Observers team scoret !!"
               << "Hans spenningsnivå er"
               << getExcitationLevel ()
               << "pass på hjerteinfarkt!" << endl;
        }ellers{
          cout << "Team scoret ikke. Yeeeih ikke noe å bekymre deg for"
               << endl;
        }
    } // sluttoppdatering ()
};
klasse Young_ConcreteObserver: public Observer
{
   offentlig:
     // Ringer foreldrekonstruktør til å registrere seg med emne
     Young_ConcreteObserver (Subject * mod, int div)
       : Observer (mod, div) {}
     // For eldre mennesker, hvis spenningsnivået
     // er over 100 risikoen for hjerteinfarkt
     ugyldig oppdatering ()
     {
        bool scoret = getSubject () -> getScored ();
        setExcitationLevel (getExcitationLevel () + 1);
        if (scoret && getExcitationLevel ()> 100)
        {
          cout << "Unge observatørs lag scoret !!"
               << "Hans spenningsnivå er"
               << getExcitationLevel ()
               << "drikker ikke og kjører!" << endl;
        }ellers{
          cout << "Team scoret ikke. Ja, ingenting å bekymre deg for"
               << endl;
       }
    } // sluttoppdatering ()
};

Hovedfunksjon
De konkrete observatørene registrerer seg selv i subjektforekomsten. Deres tilstand er spenningsnivået som er den andre parameteren. Når hendelsen utløses "subj.setScored (true)", kalles daSubject :: varsling () for å oppdatere de registrerte observatørene. I scenariet nedenfor har vi tre observatører, de unge Obs1 er overekscited og risikerer å drikke og kjøre bil, den oldObs1is også overexcited en løper en annen risiko (for hjerteinfarkt). Til slutt har youngObs2, som også er ung som den første, ingenting å bekymre seg for, fordi han ikke er for spent.

Det er viktig å merke seg at de tre observatørene oppdaterte uavhengig basert på deres tilstand (spenningsnivå) og deres type (ung eller gammel).
int main () {
   Emne subj;
   Young_ConcreteObserver youngObs1 (& subj, 100);
   Old_ConcreteObserver oldObs1 (& subj, 150);
   Young_ConcreteObserver youngObs2 (& subj, 52);
   subj.setScored (true);
}
// Utgang
// Teamet til Young Observer scoret !! Spenningsnivået hans er 101
// drikker ikke og kjører !!
// Old Observers lag scoret !! Spenningsnivået hans er 151 klokker
// ut av hjerteinfarkt! Team scoret ikke.
// Yeeh ingenting å bekymre deg for

Det er noen fordeler med bruk av Observer-mønster, og noen få punkter som skal bemerkes når dette mønsteret skal tilnærmes [Learning Python Design Patterns].

  • Observer-mønsteret gir et design der motivet og observatøren er løst koblet. Faget trenger ikke å vite om ConcreteObserver-klassen. Enhver ny observatør kan legges til når som helst. Det er ikke nødvendig å endre emnet når en ny observatør legges til. Observatører og forsøkspersoner er ikke bundet og er uavhengige av hverandre, derfor vil endringer i emnet eller observatøren ikke påvirke hverandre.
  • Det er ikke noe alternativ for komposisjon, ettersom Observer-grensesnittet kan bli øyeblikkelig.
  • Hvis observatøren blir misbrukt, kan den lett tilføre kompleksitet og føre til ytelsesproblemer.
  • Varsler kan være upålitelige og kan føre til løpsforhold eller inkonsekvens.

Den neste bloggen vil være en rask guide til Bridge-designmønsteret. Det er et strukturelt designmønster som brukes ganske mye i bransjen. Ikke glem å like / klaffe blogginnlegget mitt og følge kontoen min. Dette for å gi meg tilfredsheten med at jeg hjalp noen medutviklere og presset meg til å fortsette å skrive. Hvis det er et spesifikt designmønster som du vil lære om, så gi beskjed så jeg kan skaffe det til deg i fremtiden.

Andre hurtigveiledninger om designmønstre:

  1. Designmønstre - En rask guide til Abstract Factory.
  2. Designmønstre - En rask guide til Bridge Pattern.
  3. Designmønstre - En rask guide til Builder Pattern.
  4. Designmønstre - En rask guide til Decorator Pattern.
  5. Designmønstre - En rask guide til Fasademønster.
  6. Designmønstre - En rask guide til observatørmønster.
  7. Design Patterns - En rask guide til Singleton Pattern.