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

Builder-mønsteret er et kreativt designmønster, der håndterer konstruktionen af ​​komplekse objekter trin for trin (eller mursten for mursten). Det er sandsynligvis det nemmeste mønster at se, hvis den eksisterende kode har brug for sådan design. Builder-mønsteret tillader oprettelse af forskellige repræsentationer af et objekt ved hjælp af den samme konstruktionskode.

Builder-mønster klassificeres i de kreative designmønstre, som handler om klassificering af objekt / objekt. Mere præcist, hvordan man effektivt bruger arv (klasseskabelsesmønstre) eller delegering (objektoprettelsesmønstre). [af designmønstre forklaret ganske enkelt]

Eksempel: Lad os starte med et eksempel på mit yndlingsemne. Mad!! Mere præcist vil eksemplet dreje sig om pizza. Pizza opdeles i tre lag, dejen, saucen og påfyldningen. Lad os nu spørge os selv, hvordan ville vi "konstruere" en pizza-genstand, der vælges blandt forskellige toppings og en række saucer.

Spørgsmål inden du designer en løsning på dette problem:

  • Hvordan ville Pizza-konstruktøren se ud?
  • Bør vi have flere overbelastningskonstruktører med parametre til alle kombinationer som saucer, toppings plus saucer osv.? Hvad hvis vi også har forskellige typer dej?
  • Hvad hvis vi senere beslutter at tilføje ost eller forskellige typer ost? Ville det være let at implementere? Hvad med afhængigheder af eksisterende kode?
  • Skal vi bare have en standardkonstruktør, der skaber en "almindelig pizza"? Ville det ikke tvinge klienten til at ringe til et antal sættere i overensstemmelse hermed? Er dette sikkert? Hvad hvis klienten glemmer, og så sender vi en almindelig pizza til kunden?

Løsningen på alle disse spørgsmål er byggemønsteret. Vi har brug for en "bygmester" til at konstruere en pizza trin for trin. Samtidig vil klienten være sikker på at "bestille" en bestemt pizza og få bygherren til at bygge den for ham.

Trin 1 - Nøgleord

  1. Repræsentation: Et objekt kan have forskellige repræsentationer. For eksempel kan en pizza have tomatmozzarellaudfald, og en anden repræsentation af pizza ville være med svampe og parmaskink.
  2. Konstruktionskode: Objekter kan konstrueres på forskellige måder, for eksempel ved hjælp af konstruktører. Konstruktører kan overbelastes, de har samme navn (klassens navn) men et andet antal / typer argumenter. Afhængigt af antallet og typen af ​​argumenter, der er sendt, kaldes den specifikke konstruktør.

Det er let at falde i den fælde at have en klasse med adskillige konstruktører, hvor hver enkelt tager et andet antal parametre. Udvikleren er tvunget til at instantisere klassen med den korrekte kombination af parametre i hver situation. Dette problem har et navn, det er et populært antimønster, der kaldes teleskopkonstruktøren, og bygmønsteret er løsningen til det. Lad os overforenkle Builder-mønsteret ved at fortumme:

Builder-mønsterets vigtigste hensigt er at have det mindste antal overbelastede konstruktører til at understøtte konstruktionen af ​​flere repræsentationer af et objekt.

Trin 2 - Diagram (som eksempel)

Lad os holde os til pizzaeksemplet. I resuméet har vi pizzaklassen, kokken og betonbyggerne, der arver fra den abstrakte bygherre. Vi forklarer diagrammet neden til top:

  • Pizza_Product: Denne klasse er den egentlige pizza. Det er repræsenteret af tre attributter: (1) Dej, (2) sauce og (3) toppings.
  • ConcreteBuilder: Hver betonbygger er ansvarlig for en bestemt repræsentation. I dette eksempel har vi Margherita og Spicy Pizza. Begge betonbyggere er ansvarlige for at ”bygge” deres egen repræsentation af pizza baseret på de tre attributter, der er anført ovenfor.
  • AbstractBuilder: Indeholder en pizza-medlemsvariabel, og betonbyggerne arver det.
  • Cook_Director: I dette eksempel er instruktøren den egentlige kok. Klassen er ansvarlig for at påbegynde konstruktionen af ​​en given repræsentation ved at sætte brikkerne sammen, så bygherren følger og tilpasser sig efter instruktørens behov.

Trin 3 - 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).

Produkt:
Dette er pizzaklassen. Det er en simpel klasse med tre sæt og en smag () -metode, der udskriver alle ingredienserne.

# inkluder 
#include  // unique_ptr
ved hjælp af navneområde std;
klasse Pizza_Product
{
offentlig:
 void setDough (const string & dough) {m_dough = dough; }
 void setSauce (const string & sauce) {m_sauce = sauce; }
 void setTopping (const string & topping) {m_topping = topping; }
void taste () const
{
  cout << "Pizza med" << m_dej << "dej,"
       << m_sauce << "sauce og"
       << m_topping << "topping. Mmmmmmm." << endl;
}
privat:
 streng m_dej;
 streng m_sauce;
 streng m_topping;
};

Abstract Builder:
Den abstrakte builder er en grænseflade, der indeholder et pizza-objekt. Det har en getter, der returnerer pizzaobjektet og en metode til at instantisere pizzaobjektet. Det erklærer også de tre bygherremetoder, der vil blive implementeret af betonbyggerne længere nede.

klasse Pizza_Builder
{
offentlig:
  virtuel ~ Pizza_Builder () {};
  Pizza_Produkt * getPizza () {return m_pizza.release (); }
  void createNewPizzaProduct ()
  {
    m_pizza = make_unique  ();
  }
  virtual void buildDough () = 0;
  virtual void buildSauce () = 0;
  virtual void buildTop () = 0;
beskyttet:
  unik_ptr  m_pizza;
};

Betonbyggere:
To eksempler på betonbyggere og to repræsentationer af en pizza. De implementerer begge deres egne build-metoder ved hjælp af m_pizza-objektet fra forældreklassen (Abstract builder)

klasse Margherita_ConcreteBuilder: offentlig Pizza_Builder
{
offentlig:
 virtual void buildDough () {m_pizza-> setDough ("cross"); }
 virtual void buildSauce () {m_pizza-> setSauce ("tomat"); }
 virtual void buildTop () {m_pizza-> setTopping ("mozzarela + basilikum"); }
};
klasse Spicy_ConcreteBuilder: offentlig Pizza_Builder
{
offentlig:
 virtual void buildDough () {m_pizza-> setDough ("pan baked"); }
 virtual void buildSauce () {m_pizza-> setSauce ("tomat + chili"); }
 virtual void buildTop () {m_pizza-> setTopping ("pepperoni + salami"); }
};

Direktør:
Denne klasse sætter alt sammen. Det har en Pizza_Builder-variabel. Den bruger makePizza () til at modtage en betonbygger som parameter. Derefter kalder build-operationerne, der fungerer for begge repræsentationer i overensstemmelse hermed. Derfor opnår vi formålet med at have en konstruktionskode til at repræsentere forskellige typer pizzaer. Metoden tastePizza () er at udskrive indholdet af en pizza.

klasse Cook_Director
{
offentlig:
 void tastePizza () {m_pizzaBuilder-> getPizza () -> taste (); }
void makePizza (Pizza_Builder * pb)
 {
   m_pizzaBuilder = pb;
   m_pizzaBuilder-> createNewPizzaProduct ();
   m_pizzaBuilder-> buildDough ();
   m_pizzaBuilder-> buildSauce ();
   m_pizzaBuilder-> buildTop ();
 }
privat:
 Pizza_Builder * m_pizzaBuilder;
};

Hoved (klient):
 Hovedmetoden fungerer som klient (den samme som de tidligere guider). Det er så let for klienten at være i stand til at opbygge forskellige repræsentationer af en pizza. Vi har brug for instruktøren, og derefter ved blot at videregive to forskellige konkrete bygherrer som en parameter til themakePizza, vil vi være i stand til at smage to forskellige typer pizzaer.

int main ()
{
  Cook_Director cook;
  Margherita_ConcreteBuilder margheritaBuilder;
  Spicy_ConcreteBuilder spicyPizzaBuilder;
  cook.makePizza (& margheritaBuilder);
  cook.tastePizza ();
  cook.makePizza (& spicyPizzaBuilder);
  cook.tastePizza ();
}
// Output
// Pizza med krydsdej, tomatsauce og mozzarela + basilikum. // Mmmmmmm.
// Pizza med pandebagt dej, tomat + chili sauce og
// pepperoni + salami topping. Mmmmmmm.

Lad os opsummere fordelene ved dette mønster:

  • Der er mange mulige repræsentationer, men kun et fælles input.
  • Vi har en standardprotokol til oprettelse af alle mulige repræsentationer. Trinene i denne protokol er tydeligt eksponeret af en Builder-interface.
  • Der er en afledt konkret klasse for hver målrepræsentation.
  • Det er let for en udvikler at tilføje en ny selvstændig og uafhængig repræsentation (af en Pizza) uden frygt for at bryde noget andet.
  • Klienten kan blot registrere ConcreteBuilder til direktøren og få den forventede repræsentation.

Den næste blog vil være en hurtig guide til Decorator-designmønsteret. Det er et strukturelt mønster, som er et must for dit videnlager. 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.