Designmønstre - En hurtig guide til Observer-mønster.

Observatormønster er et meget almindeligt anvendt mønster. Faktisk er det så almindeligt, at der standardiseres i mange programmeringssprog / biblioteker. I Java findes det injava.util.Observer (udskrevet i Java 9). I Python er det så tæt som apip-installation af mønsterobservatør. I C ++ kan vi undertiden bruge boost-bibliotek, mere præcist # inkluder . Imidlertid er det meget brugt i industrien som en skræddersyet løsning. For at kunne bruge det korrekt og forstå dets kompleksitet, er vi nødt til at dykke ind og udforske den.

Observatormønster klassificeres blandt de adfærdsmæssige designmønstre. Adfærdsmæssige designmønstre er mest specifikt beskæftiget med kommunikation mellem klasser / objekter. [af designmønstre forklaret ganske enkelt]

Hvad er et observatormønster? Bortset fra en gåmonitor, der sender analogt tv (som på billedet). Mønsterets mål er at definere et en-til-mange-forhold, således at når et objekt ændrer tilstand, bliver de andre underrettet og opdateret automatisk. Mere præcist ønsker den at blive informeret om begivenheder, der finder sted i systemet. Lad os sætte brikkerne i puslespillet sammen i tre trin.

Trin 1 - Nøgleord

Definition af nøgleord er den hemmelige opskrift i denne serie af hurtigguider. Denne metode hjalp mig med virkelig at forstå designmønstre, hardkode dem i mit sind og forstå forskellene mellem andre designmønstre.

  1. Emne: Det betragtes som indehaveren af ​​information, data eller forretningslogik.
  2. Registrer / vedhæft: Observatører registrerer sig selv til emnet, fordi de ønsker at blive underrettet, når der sker en ændring.
  3. Begivenhed: Begivenheder fungerer som en trigger i emnet, så alle observatører bliver underrettet.
  4. Underret: Afhængigt af implementeringen kan emnet "skubbe" information til observatørerne, eller kan observatørerne "trække", hvis de har brug for oplysninger fra emnet.
  5. Opdatering: Observatører opdaterer deres tilstand uafhængigt af andre observatører, men deres tilstand kan ændre sig afhængigt af den udløste begivenhed.

Trin 2 - Diagram

Lad os opdele dette design i forskellige klasser for at forenkle dette lidt.

  • ConcreteObservers er klasser, der indeholder oplysninger, der er specifikke for den nuværende instans. Opdateringsfunktionen kaldes af emnets besked () -operation. Observatørerne opdaterer uafhængigt baseret på deres nuværende tilstand.
  • Observatøren er den overordnede klasse for de konkrete observatører. Det indeholder et emneeksempel. Når en observatør initialiseres, registrerer / knytter den sig til emnet.
  • Emneklassen har en liste eller en samling af observatører. Når en begivenhed udløses, kalder den underret () -operationen, der løber gennem alle observatører ved at kalde deres opdateringsfunktion.

Trin 3 - Kode efter eksempel

Jeg vil foreslå at kopiere kodeklassen efter klasse fra mit git-arkiv "Andreas Poyias" eller uddragene nedenfor (i den angivne rækkefølge) og indsætte den i en hvilken som helst af de tilgængelige online C ++ -redaktører som c ++ shell, jdoodle, onlineGDB og køre det for at observere output. Læs derefter kommentarer eller beskrivelse nedenfor. Brug din tid på at læse den grundigt (det betyder et minut, ikke mindre og ikke mere).

Eksempel: Overvej et fodboldkamp. Mange tilhængere ser spillet. Vi delte tilhængerne i to kategorier efter alder, unge og gamle. Når deres hold scorer et mål, reagerer tilhængerne forskelligt efter deres alder og deres spændingsniveau.
Lad os tale med udtryk, der bruges til observatørmønsteret:

  • Spillet er emnet, og tilhængere er observatører.
  • Alle observatører er knyttet / registreret til emnet, og de får besked, når deres fodboldhold scorer (trigger-begivenheden er, hvis deres hold scorer).
  • Observatørerne opdaterer deres opførsel afhængigt af den modtagne anmeldelse.

Emne
For denne klasse har vi brug for adgang til en liste over observatører. Når observatørerne er ved at registrere, kalder de theattach-funktionen (denne) for at føje sig selv til den tilgængelige liste (dette er en observatørs eksempel). Når en begivenhed udløses, wenotify () alle observatører til uafhængigt at opdatere deres tilstand. I dette eksempel er udløseren, hvis observatørens fodboldhold scorede.

# inkluder 
#include 
ved hjælp af navneområde std;
klasseemne {
    vektor  observatører;
    bool scorede; // trigger, begivenhed
offentlig:
    // registrere observatører
    void attach (Observer * obs) {
        observers.push_back (obs);
    }
   
   // Dette er begivenheden
   // indstil if-scoringen og underret ALLE observatører
   void setScored (bool Score) {
      scoret = score;
      underrette();
   }
bool getScored () {
      returneret score;
   }
   // underrette implementering er længere nede
   //, så scriptet samles og kører
   ugyldig anmeldelse ();
};

Observer
Denne klasse er afhængig af det emne, den er registreret med. Når konkrete observatører initialiseres, knytter de sig til projektet. I dette eksempel er hver observatørs tilstand hans begejstring Uden for spillet.

klasse observatør
{
    Emne * subj;
    int spænding niveau; // stat
  offentlig:
    Observatør (Emne * mod, int excLevel)
    {
        subj = mod;
        ExcitationNiveau = excLevel;
        // Observatører registrerer / vedhæfter sig emnet
        subj-> vedhæfte (dette);
    }
    virtual void update () = 0;
  beskyttet:
    Emne * getSubject () {
       returnere subj;
    }
    void setExcitationLevel (int excLevel) {
       ExcitationNiveau = excLevel;
    }
    int getExcitationLevel () {
       vende tilbage spænding;
    }
};

Dette er theSubject :: notify () -erklæringen, og som vi nævnte før dens opgave er at underrette alle observatører om at opdatere deres tilstand.

void Emne :: underrette () {
  for (int i = 0; i  opdatering ();
}

Betonobservatører
De konkrete observatører arver fra Observer-klassen, og de skal alle have opdateringsfunktionen. I dette eksempel skelnes de konkrete observatører mellem unge og gamle tilhængere. Hvis deres spændingsniveau bliver for højt, har de ældre tilhængere risikoen for hjerteanfald, og de yngre har risikoen for at drikke og køre. Deres tilstand opdateres uafhængigt, som vi vil bevise i hovedfunktionen længere nedenfor.

klasse Old_ConcreteObserver: public Observer
{
   offentlig:
     // Opfordrer overordnet konstruktør til at registrere sig med emnet
     Old_ConcreteObserver (Emne * mod, int div)
        : Observatør (mod, div) {}
     // For ældre mennesker, hvis spændingsniveauet
     // er over 150, de risikerer hjerteanfald
     ugyldig opdatering ()
     {
        bool scorede = getSubject () -> getScored ();
        setExcitationLevel (getExcitationLevel () + 1);
        if (scoret && getExcitationLevel ()> 150)
        {
          cout << "Gamle Observers hold scorede !!"
               << "Hans spændingsniveau er"
               << getExcitationLevel ()
               << "Vær opmærksom på hjerteanfald!" << endl;
        }andet{
          cout << "Hold scorede ikke. Yeeeih intet at bekymre sig om"
               << endl;
        }
    } // slutopdatering ()
};
klasse Young_ConcreteObserver: public Observer
{
   offentlig:
     // Opfordrer overordnet konstruktør til at registrere sig med emnet
     Young_ConcreteObserver (Emne * mod, int div)
       : Observatør (mod, div) {}
     // For ældre mennesker, hvis spændingsniveauet
     // er over 100 risici for hjerteanfald
     ugyldig opdatering ()
     {
        bool scorede = getSubject () -> getScored ();
        setExcitationLevel (getExcitationLevel () + 1);
        if (scoret && getExcitationLevel ()> 100)
        {
          cout << "Young Observers hold scorede !!"
               << "Hans spændingsniveau er"
               << getExcitationLevel ()
               << "drikker ikke og kør ikke !!" << endl;
        }andet{
          cout << "Hold scorede ikke. Ja, intet at bekymre sig om"
               << endl;
       }
    } // slutopdatering ()
};

Hovedfunktion
De konkrete observatører registrerer sig selv i subjektforekomsten. Deres tilstand er spændingsniveauet, som er den anden parameter. Når begivenheden udløses "subj.setScored (true)", kaldes daSubject :: notify () for at opdatere de registrerede observatører. I scenariet herunder har vi tre observatører, den unge Obs1 er overopspændt og risikerer at drikke og køre, den gamle Obs1 er også overdrevent en løber en anden risiko (for hjerteanfald). Til sidst har youngObs2, der også er ung som den første, ikke noget at bekymre sig om, da han ikke er for ophidset.

Det er vigtigt at bemærke, at de tre observatører opdaterede uafhængigt baseret på deres tilstand (spændingsniveau) 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 (sand);
}
// Output
// Young Observers hold scorede !! Hans spændingsniveau er 101
// drikker ikke og kør ikke !!
// Old Observer hold scorede !! Hans spændingsniveau er 151 ur
// ud af hjerteanfald! Hold scorede ikke.
// Yeeh intet at bekymre sig om

Der er et par fordele ved brugen af ​​Observer-mønster og et par punkter, der skal bemærkes, når dette mønster skal nås [Learning Python Design Patterns].

  • Observer-mønsteret giver et design, hvor motivet og observatøren er løst koblet. Emnet behøver ikke at vide om klassen ConcreteObserver. Enhver ny observatør kan tilføjes når som helst. Det er ikke nødvendigt at ændre emnet, når en ny observatør tilføjes. Observatører og motiver er ikke bundet og er uafhængige af hinanden, derfor vil ændringer i emnet eller observatøren ikke påvirke hinanden.
  • Der er ingen mulighed for komposition, da Observer-interface kan blive instantieret.
  • Hvis observatøren misbruges, kan den let tilføje kompleksitet og føre til præstationsproblemer.
  • Underretninger kan være upålidelige og kan resultere i raceforhold eller inkonsekvens.

Den næste blog vil være en hurtig guide til Bridge-designmønsteret. Det er et strukturelt designmønster, der bruges ret meget i branchen. Glem ikke at lide / klappe mit blog-indlæg og følge min konto. Dette er for at give mig den tilfredshed, at jeg hjalp nogle medudviklere og presser mig til at fortsætte med at skrive. Hvis der er et specifikt designmønster, som du gerne vil lære om, så fortæl mig det, så jeg kan give det til dig i fremtiden.

Andre hurtigguider om designmønstre:

  1. Designmønstre - En hurtig guide til Abstract Factory.
  2. Designmønstre - En hurtig guide til Bridge Pattern.
  3. Designmønstre - En hurtig guide til Builder Pattern.
  4. Designmønstre - En hurtig guide til Decoratormønster.
  5. Designmønstre - En hurtig guide til Fasademønster.
  6. Designmønstre - En hurtig guide til observatørmønster.
  7. Designmønstre - En hurtig guide til Singleton-mønster.