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

Decorator-mønsteret er et strukturelt mønster, der giver dig mulighed for at knytte yderligere funktionaliteter til et objekt dynamisk. Med andre ord har klienten friheden til at oprette et objekt og derefter udvide det ved at tilføje en række "funktioner" til det. En god analogi til at forenkle dette mønster er: “Indpakning af en gave, lægning i en kasse og indpakning af kassen”.

Decorator-mønsteret er klassificeret blandt strukturelle designmønstre, som handler om klasse- og objektsammensætning. Strukturelle klasseskabningsmønstre bruger arv til at komponere grænseflader. Strukturelle objektmønstre definerer måder at komponere objekter for at få ny funktionalitet. [af designmønstre forklaret ganske enkelt]

En rygsæk i det perfekte eksempel på et dekoratørmønster:

  • I dag kan rygsækkene have en række funktioner. Funktionerne kan variere fra noget så simpelt som en bærbar slot, sidelommer eller endda en power-bank til USB-opladning.
  • Hovedmålet med Decorator-mønsteret er at give klienten mulighed for at tilføje de funktioner, der kræves, dynamisk, sikkert og på den nemmest mulige måde. Den skal være lige ligetil og ryddig som montering af rygsæk på billedet.
  • Kodestykket nedenfor er med vilje skrevet, da det konvergerer så pænt med det citat, vi nævnte ovenfor: “Indpakning af en gave, lægning i en kasse og indpakning af kassen”. Vi samler en rygsæk, som vi tilføjer en USB-oplader, som vi tilføjer en bærbar slot, som vi tilføjer ...
int main // klienten
{
  IBackpack * bp = ny LaptopSlot (ny UsbCharge (...))));
  retur 1;
}

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.

  • Fleksibilitet: Vi ønsker at give klienten magt og fleksibilitet til dynamisk at føje enhver funktion til en komponent / objekt, der kan betragtes som værdifuld.
  • Udvid funktionalitet: Titlen kan være lidt vildledende, dette mønster handler ikke kun om at "dekorere" et bestemt objekt, men det handler hovedsageligt om at udvide dets funktionalitet.

Trin 2 - Diagrammer ved eksempel

Lad os begynde at forklare diagrammet fra bund til top. Målet er at "samle" en rygsæk og tilføje flere funktioner til den.

  • Betondekoratører: Vi har tre eksempler på disse klasser, der er ansvarlige for at udvide en ekstra funktionalitet hver: (1) LaptopSlot, (2) USBCharge, (3) WaterBottle. De har implementeringen af ​​funktionaliteten, og de kan "samle" en rygsæk i overensstemmelse hermed. Bemærk, at de har en konstruktør, der modtager en dekoratør som parameter.
  • Dekoratør: Denne klasse henter ovennævnte klasser og arver fra den komponent, der er IBackpack. Dekoratøren har også et eksempel på IBackpack. Efter IBackpackis-øjeblikket er det brugt inden for samlingen () -metoden.
  • Betonkomponent: Denne klasse er det vigtigste brik i puslespillet, da det er nøglen til at knytte alt sammen. Det er den komponent (rygsæk), der er i den mest almindelige form, den kunne få. For eksempel består en almindelig rygsæk kun af ”skulderremme og hovedrum”. Den almindelige rygsæk fungerer som en start på en kæde. Det ledes til dekoratorkonstruktøren og overføres selv til konstruktøren af ​​en betondekoratør (for at tilføje specifikke funktionaliteter, dvs. en bærbar åbning), som kan føres til en anden konstruktør af en betondekoratør og en anden og så videre.
  • Komponent: Det er et abstrakt billede af det objekt, vi vil dekorere. Vi kan have forskellige konkrete komponenter, der arver det. I dette eksempel kunne vi adskille “PlainBackpack” som “OfficeBackpack”, “CampingBackpack”, “HikingBackpack”, men vi vælger at holde det enkelt.

Trin 23 - kode ved 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 af ​​de tilgængelige online C ++ -redaktører som c ++ shell, jdoodle, onlineGDBand køre det for at observere output. Læs derefter kommentarer eller beskrivelse nedenfor. Tag dig tid til at læse den grundigt (det betyder et minut, ikke mindre og ikke mere).

IBackpack:
Følgende kodestykker er en enkel arv, IBackpackis, der er arvet af PlainBackpackclass. Alle afledte klasser skal implementere samling (), da det er en ren virtuel funktion = 0 ;. En almindelig rygsæk har kun skulderstropper og hovedrummet.

# inkluder 
ved hjælp af navneområde std;

klasse IBackpack
{
offentlig:
  virtuelt tomrumssamling () = 0;
  virtuel ~ IBackpack () {}
};

klasse PlainBackpack: offentlig IBackpack
{
offentlig:
  virtuelt tomrumssamling () {cout << "\ n Skulderstrimler og hovedkammer";}
};

BackpackDecorator:
Ovenstående uddrag er ansvarligt for konstruktionen af ​​en almindelig rygsæk. Lad os nu pynte det med BackpackDecorator. Dekoratøren arver fraIBackpack, hvilket betyder, at den skal implementere samlingen () -metoden. Det indeholder også et IBackpackobjekt, der bruges til at delegere implementeringen af ​​metoden assembler () afhængigt af typen m_decorator.

klasse RygsækDekorator: offentlig IBackpack
{
offentlig:
  BackpackDecorator (IBackpack * decorator): m_Decorator (decorator) {}
  
  virtual void assemble ()
  {
    m_Decorator-> samle ();
  }
privat:
  IBackpack * m_Decorator;
};

Betondekoratører:
Uddraget nedenfor viser tre forskellige dekoratører, der er afledt af klassenBackpackDecorator, som selv arver fraIBackpack. I dette eksempel er de alle identiske bortset fra implementeringen af ​​samlingen (). Den første tilføjer en bærbar computer, den anden tilføjer en UBCharge og den tredje tilføjer en vandbottle.

klasse WithL laptopSlot: public BackpackDecorator
{
offentlig:
  WithL laptopSlot (IBackpack * dcrator): BackpackDecorator (dcrator) {}
  virtual void assemble ()
  {
    BackpackDecorator :: samle ();
    cout << "+ LaptopSlot";
  }
};
 
klasse WithUSBCharge: public BackpackDecorator
{
offentlig:
    WithUSBCharge (IBackpack * dcrator): BackpackDecorator (dcrator) {}
    virtual void assemble ()
    {
        BackpackDecorator :: samle ();
        cout << "+ USBCharge";
    }
};
 
klasse WithWaterBottle: public BackpackDecorator
{
offentlig:
    WithWaterBottle (IBackpack * dcrator): BackpackDecorator (dcrator) {}
    virtual void assemble ()
    {
        BackpackDecorator :: samle ();
        cout << "+ WaterBottle";
    }
};

Hoved (klient):
Hovedmetoden fungerer som klient (den samme som de tidligere guider). Vi er endelig i stand til at sætte alle brikkerne i puslespillet sammen. Men inden vi gør det, lad os huske, hvad der blev nævnt i første afsnit i bloggen "Indpakning af en gave, læg den i en kasse og indpakning af kassen". For at forstå dette skal vi læse konstruktionen af ​​rygsækken (i uddraget nedenfor) i omvendt rækkefølge:

  1. Opret en PlainBackpack.
  2. Overfør den til BackpackDecorator.
  3. Hvilket passerer det sammen for at blive dekoreret med en bærbar slot.
  4. Til gengæld overføres det til at blive dekoreret med en USB-opladning.
  5. Endelig er "kassen" "indpakket" med en vandflaske.

Det er også vigtigt at overholde udskriftsrækkefølgen, når samlingen () kaldes. Ordren er relateret til, hvordan konstruktørerne blev initialiseret. Det starter igen fra den almindelige rygsæk og er dekoreret hele vejen for at nå vandflaske.

int main ()
{
  IBackpack * pBackpack =
   ny WithWaterBottle (// 5
    ny WithUSBCharge (// 4
     ny WithL laptopSlot (// 3
      ny BackpackDecorator (// 2
       ny PlainBackpack ())))); // 1

  pBackpack-> samle ();
  slet pBackpack;

  retur 0;
}
// Output
// Skulderstropper og hovedkammer + LaptopSlot + USBCharge
// + WaterBottle

Enkelheden, der tilbydes kunden, er en af ​​de største fordele.

  • Klienten har magten til dynamisk at samle en rygsæk med alle tilgængelige funktioner.
  • Det er enkelt, let og sikkert.
  • Klienten behøver ikke at blande sig med koden.
  • Tilføjelse af en ekstra "afledt" dekoratør er enkel og uafhængig af andre afledte dekoratører.

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 i kommentarerne herunder, så jeg kan give det til dig i de næste par uger.

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.