Comprendi il "motivo decorativo" con un esempio reale


167

Stavo studiando il motivo decorativo come documentato nel GOF .

Per favore, aiutami a capire il motivo del decoratore . Qualcuno potrebbe dare un esempio di caso d'uso di dove questo è utile nel mondo reale?


8
Potete trovare qui alcuni esempi realworld in Java API: stackoverflow.com/questions/1673841/...
BalusC

Un articolo che mostra i vantaggi del motivo decorativo con semplici esempi: dzone.com/articles/is-inheritance-dead
nbilal

Risposte:


226

Il modello Decorator raggiunge un unico obiettivo di aggiungere dinamicamente responsabilità a qualsiasi oggetto.

Prendi in considerazione un caso di una pizzeria. Nella pizzeria venderanno alcune varietà di pizza e forniranno anche condimenti nel menu. Ora immagina una situazione in cui la pizzeria deve fornire i prezzi per ogni combinazione di pizza e topping. Anche se ci sono quattro pizze di base e 8 condimenti diversi, l'applicazione impazzirebbe mantenendo tutte queste combinazioni concrete di pizze e condimenti.

Ecco che arriva il motivo del decoratore.

Come per il modello del decoratore, implementerai i condimenti poiché i decoratori e le pizze saranno decorati dai decoratori di questi condimenti. Praticamente ogni cliente vorrebbe condimenti del suo desiderio e l'importo del conto finale sarà composto dalle pizze di base e condimenti aggiuntivi ordinati. Ogni decoratore topping saprebbe delle pizze che sta decorando ed è il prezzo. Il metodo GetPrice () dell'oggetto Topping restituisce il prezzo cumulativo sia della pizza che del topping.

MODIFICARE

Ecco un esempio di codice di spiegazione sopra.

public abstract class BasePizza
{
    protected double myPrice;

    public virtual double GetPrice()
    {
        return this.myPrice;
    }
}

public abstract class ToppingsDecorator : BasePizza
{
    protected BasePizza pizza;
    public ToppingsDecorator(BasePizza pizzaToDecorate)
    {
        this.pizza = pizzaToDecorate;
    }

    public override double GetPrice()
    {
        return (this.pizza.GetPrice() + this.myPrice);
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //Client-code
        Margherita pizza = new Margherita();
        Console.WriteLine("Plain Margherita: " + pizza.GetPrice().ToString());

        ExtraCheeseTopping moreCheese = new ExtraCheeseTopping(pizza);
        ExtraCheeseTopping someMoreCheese = new ExtraCheeseTopping(moreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese: " + someMoreCheese.GetPrice().ToString());

        MushroomTopping moreMushroom = new MushroomTopping(someMoreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom: " + moreMushroom.GetPrice().ToString());

        JalapenoTopping moreJalapeno = new JalapenoTopping(moreMushroom);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom with Jalapeno: " + moreJalapeno.GetPrice().ToString());

        Console.ReadLine();
    }
}

public class Margherita : BasePizza
{
    public Margherita()
    {
        this.myPrice = 6.99;
    }
}

public class Gourmet : BasePizza
{
    public Gourmet()
    {
        this.myPrice = 7.49;
    }
}

public class ExtraCheeseTopping : ToppingsDecorator
{
    public ExtraCheeseTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 0.99;
    }
}

public class MushroomTopping : ToppingsDecorator
{
    public MushroomTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}

public class JalapenoTopping : ToppingsDecorator
{
    public JalapenoTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}

104
Non mi piace questo modello un po '. Forse è l'esempio però. Il problema principale che ho con esso in termini di OOD è che un condimento non è una pizza . Chiedere il condimento per il prezzo della pizza a cui è applicata non si adatta a me. È un esempio molto ponderato e dettagliato, quindi non intendo bussarti per questo.
Tom W,

39
@TomW Penso che parte del problema sia la denominazione. Tutte le classi "Topping" dovrebbero essere chiamate "PizzaWith <Topping>". Ad esempio, "PizzaWithMushrooms".
Josh Noe,

2
A mio avviso, i decoratori sono meglio usati nel modo più piatto possibile. Con questo intendo il minor numero possibile di "decoratori che avvolgono decoratori". Quindi forse questo esempio non è il più adatto. Ma è abbastanza approfondito, il che è bello.
thekingoftruth,

17
Da un'altra prospettiva questo non è nemmeno vicino al "mondo reale". Nel mondo reale non dovresti ricompilare ogni volta che devi aggiungere un nuovo condimento nel menu (o cambiare il prezzo). I condimenti sono (di solito) memorizzati nel database e quindi rendono inutile l'esempio sopra.
Stelios Adamantidis,

4
^ Questo. Penso che questo sia ciò che mi ha infastidito mentre studiavo questo schema. Se fossi un'azienda di software e scrivessi software per pizzerie, non vorrei ricompilare e rispedire ogni volta. Vorrei aggiungere una riga in una tabella nel backend o qualcosa che possa facilmente prendersi cura delle loro esigenze. Ben detto, @Stelios Adamantidis. Immagino che la forza più grande degli schemi sarebbe la modifica delle classi di terze parti.
Canucklesandwich,

33

Questo è un semplice esempio di aggiunta dinamica di un nuovo comportamento a un oggetto esistente o al motivo Decoratore. A causa della natura di linguaggi dinamici come Javascript, questo modello diventa parte del linguaggio stesso.

// Person object that we will be decorating with logging capability
var person = {
  name: "Foo",
  city: "Bar"
};

// Function that serves as a decorator and dynamically adds the log method to a given object
function MakeLoggable(object) {
  object.log = function(property) {
    console.log(this[property]);
  }
}

// Person is given the dynamic responsibility here
MakeLoggable(person);

// Using the newly added functionality
person.log('name');


Semplice e preciso! Ottimo esempio!
nagendra547,

1
Non penso che il concetto di Decorator Pattern sia applicabile qui. In realtà non è affatto un modello !. Sì, stai aggiungendo un nuovo metodo in fase di esecuzione. E probabilmente all'interno di un switcho un semplice if, si sarebbe in grado di affermare che questo è un ottimo esempio di aggiunta dinamica di comportamento a una classe. MA, abbiamo bisogno di almeno due classi per definire un decoratore e oggetti decorati in questo modello.
Iman,

1
@Zich Capisco che non c'è decoratore nel mio esempio, ma è stato risolto facilmente aggiungendo una funzione che funge da decoratore. Ma c'è un oggetto decorato nel mio esempio. Lo schema dice da qualche parte che hai bisogno di due classi in particolare?
Anurag,

18

Vale la pena notare che il modello di i / o Java si basa sul modello di decorazione. La stratificazione di questo lettore in cima a quel lettore in cima a ... è un esempio davvero reale di decoratore.


Ci sono altri esempi in vere API pubbliche? Questo è l'unico che conosco.
Josiah Yoder

Sembra che tutte le funzioni wrapper in natura abbiano una sorta di motivo decorativo incorporato, è quello che penso che sia?
Harvey Lin,

Buon esempio !!
nagendra547,

8

Esempio - Scenario- Supponiamo che tu stia scrivendo un modulo di crittografia. Questa crittografia può crittografare il file clear utilizzando DES - Standard di crittografia dei dati. Allo stesso modo, in un sistema è possibile avere la crittografia come AES - Advance standard di crittografia. Inoltre, puoi avere la combinazione di crittografia: prima DES, poi AES. Oppure puoi avere prima AES, poi DES.

Discussione: come gestirai questa situazione? Non è possibile continuare a creare l'oggetto di tali combinazioni, ad esempio AES e DES, per un totale di 4 combinazioni. Pertanto, è necessario disporre di 4 singoli oggetti. Ciò diventerà complesso all'aumentare del tipo di crittografia.

Soluzione - Continuare a costruire lo stack - combinazioni a seconda delle necessità - in fase di esecuzione. Un altro vantaggio di questo approccio allo stack è che puoi rilassarlo facilmente.

Ecco la soluzione - in C ++.

Innanzitutto, hai bisogno di una classe base - un'unità fondamentale dello stack. Puoi pensare come base dello stack. In questo esempio, è un file chiaro. Seguiamo sempre il polimorfismo. Crea prima una classe di interfaccia di questa unità fondamentale. In questo modo, puoi implementarlo come desideri. Inoltre, non è necessario pensare alla dipendenza mentre si include questa unità fondamentale.

Ecco la classe di interfaccia -

class IclearData
{
public:

    virtual std::string getData() = 0;
    virtual ~IclearData() = 0;
};

IclearData::~IclearData()
{
    std::cout<<"Destructor called of IclearData"<<std::endl;
}

Ora implementa questa classe di interfaccia -

class clearData:public IclearData
{
private:

    std::string m_data;

    clearData();

    void setData(std::string data)
        {
            m_data = data;
        }

public:

    std::string getData()
    {
        return m_data;
    }

    clearData(std::string data)
    {
        setData(data);
    }

    ~clearData()
    {
        std::cout<<"Destructor of clear Data Invoked"<<std::endl;
    }

};

Ora, facciamo una classe astratta decoratore - che può essere estesa per creare qualsiasi tipo di sapore - qui il sapore è il tipo di crittografia. Questa classe astratta decoratore è correlata alla classe base. Pertanto, il decoratore "è un" tipo di classe di interfaccia. Pertanto, è necessario utilizzare l'ereditarietà.

class encryptionDecorator: public IclearData
{

protected:
    IclearData *p_mclearData;

    encryptionDecorator()
    {
      std::cout<<"Encryption Decorator Abstract class called"<<std::endl;
    }

public:

    std::string getData()
    {
        return p_mclearData->getData();
    }

    encryptionDecorator(IclearData *clearData)
    {
        p_mclearData = clearData;
    }

    virtual std::string showDecryptedData() = 0;

    virtual ~encryptionDecorator() = 0;

};

encryptionDecorator::~encryptionDecorator()
{
    std::cout<<"Encryption Decorator Destructor called"<<std::endl;
}

Ora creiamo una classe di decorazione in calcestruzzo - Tipo di crittografia - AES -

const std::string aesEncrypt = "AES Encrypted ";

class aes: public encryptionDecorator
{

private:

    std::string m_aesData;

    aes();

public:

    aes(IclearData *pClearData): m_aesData(aesEncrypt)
    {
        p_mclearData = pClearData;
        m_aesData.append(p_mclearData->getData());
    }

    std::string getData()
        {
            return m_aesData;
        }

    std::string showDecryptedData(void)
    {
        m_aesData.erase(0,m_aesData.length());
        return m_aesData;
    }

};

Ora, supponiamo che il tipo di decoratore sia DES -

const std :: string desEncrypt = "DES Encrypted";

class des: public encryptionDecorator
{

private:

    std::string m_desData;

    des();

public:

    des(IclearData *pClearData): m_desData(desEncrypt)
    {
        p_mclearData = pClearData;
        m_desData.append(p_mclearData->getData());
    }

    std::string getData(void)
        {
            return m_desData;
        }

    std::string showDecryptedData(void)
    {
        m_desData.erase(0,desEncrypt.length());
        return m_desData;
    }

};

Facciamo un codice client per usare questa classe decoratore -

int main()
{
    IclearData *pData = new clearData("HELLO_CLEAR_DATA");

    std::cout<<pData->getData()<<std::endl;


    encryptionDecorator *pAesData = new aes(pData);

    std::cout<<pAesData->getData()<<std::endl;

    encryptionDecorator *pDesData = new des(pAesData);

    std::cout<<pDesData->getData()<<std::endl;

    /** unwind the decorator stack ***/
    std::cout<<pDesData->showDecryptedData()<<std::endl;

    delete pDesData;
    delete pAesData;
    delete pData;

    return 0;
}

Vedrai i seguenti risultati:

HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
DES Encrypted AES Encrypted HELLO_CLEAR_DATA
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Destructor called
Destructor called of IclearData
Encryption Decorator Destructor called
Destructor called of IclearData
Destructor of clear Data Invoked
Destructor called of IclearData

Ecco il diagramma UML - Rappresentazione di classe di esso. Nel caso, desideri saltare il codice e concentrarti sull'aspetto del design.

inserisci qui la descrizione dell'immagine


1
l'esempio non è più adatto a strategy pattern?
exexzian,

@exexzian Sì, i miei studenti mi suggeriscono costantemente un elenco di strategie per questo tipo di problema, e sembra anche la soluzione più pulita per me.
Josiah Yoder,

No, con il modello di strategia non è possibile combinare i metodi di crittografia. Quindi dovresti creare una classe di strategia per ogni possibile combinazione.
Deetz,

4

Il motivo Decoratore ti aiuta a cambiare o configurare una funzionalità del tuo oggetto concatenando altre sottoclassi simili di questo oggetto.

Il miglior esempio potrebbe essere rappresentato dalle classi InputStream e OutputStream nel pacchetto java.io

    File file=new File("target","test.txt");
    FileOutputStream fos=new FileOutputStream(file);
    BufferedOutputStream bos=new BufferedOutputStream(fos);
    ObjectOutputStream oos=new ObjectOutputStream(bos);


    oos.write(5);
    oos.writeBoolean(true);
    oos.writeBytes("decorator pattern was here.");


//... then close the streams of course.

In questo caso, la catena di chiamata inizia da ObjectOutputStream, quindi arriva fino alla classe File, quindi la classe File restituisce il valore, quindi le altre tre sottoclassi le somma tutte e infine, il valore del metodo ObjectOutputStream restituisce, è che corretto?
Harvey Lin,

3

Che cos'è Decorator Design Pattern in Java.

La definizione formale del modello Decorator dal libro GoF (Design Patterns: Elements of Reusable Object-Oriented Software, 1995, Pearson Education, Inc. Publishing come Pearson Addison Wesley) afferma che puoi,

"Associare ulteriori responsabilità a un oggetto in modo dinamico. I decoratori offrono un'alternativa flessibile alla sottoclasse per estendere la funzionalità."

Diciamo che abbiamo una pizza e vogliamo decorarla con condimenti come pollo Masala, cipolla e mozzarella. Vediamo come implementarlo in Java ...

Programma per dimostrare come implementare Decorator Design Pattern in Java.

Pizza.java:

<!-- language-all: lang-html -->

package com.hubberspot.designpattern.structural.decorator;

public class Pizza {

public Pizza() {

}

public String description(){
    return "Pizza";
}

}



package com.hubberspot.designpattern.structural.decorator;

public abstract class PizzaToppings extends Pizza {

public abstract String description();

}

package com.hubberspot.designpattern.structural.decorator;

public class ChickenMasala extends PizzaToppings {

private Pizza pizza;

public ChickenMasala(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + " with chicken masala, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class MozzarellaCheese extends PizzaToppings {

private Pizza pizza;

public MozzarellaCheese(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "and mozzarella cheese.";
}
}



package com.hubberspot.designpattern.structural.decorator;

public class Onion extends PizzaToppings {

private Pizza pizza;

public Onion(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "onions, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class TestDecorator {

public static void main(String[] args) {

    Pizza pizza = new Pizza();

    pizza = new ChickenMasala(pizza);
    pizza = new Onion(pizza);
    pizza = new MozzarellaCheese(pizza);

    System.out.println("You're getting " + pizza.description());

}

}

3

Ho usato ampiamente il modello Decorator nel mio lavoro. Ho pubblicato un post sul mio blog su come usarlo con la registrazione.


Non mi piace che tu abbia appena lanciato un link come risposta. Ma il tuo articolo sul blog è così utile che ho dovuto solo votare :). Adesso lo capisco davvero. Tutti vengono con la pizza e voi con un esempio perfetto.
Niklas Raab,

2

Il motivo decorativo consente di aggiungere dinamicamente il comportamento agli oggetti.

Facciamo un esempio in cui è necessario creare un'app che calcola il prezzo di diversi tipi di hamburger. È necessario gestire diverse varianti di hamburger, come "grande" o "con formaggio", ognuna delle quali ha un prezzo rispetto all'hamburger di base. Ad esempio aggiungere $ 10 per hamburger con formaggio, aggiungere $ 15 extra per hamburger di grandi dimensioni, ecc.

In questo caso potresti essere tentato di creare sottoclassi per gestirle. Potremmo esprimerlo in Ruby come:

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

Nell'esempio sopra, la classe BurgerWithCheese eredita da Burger e sovrascrive il metodo del prezzo per aggiungere $ 15 al prezzo definito nella super classe. Dovresti anche creare una classe LargeBurger e definire il prezzo relativo a Burger. Ma devi anche definire una nuova classe per la combinazione di "grande" e "con formaggio".

Cosa succede se dobbiamo servire "hamburger con patatine fritte"? Abbiamo già 4 classi per gestire quelle combinazioni e dovremo aggiungerne altre 4 per gestire tutte le combinazioni delle 3 proprietà: "grande", "con formaggio" e "con patatine fritte". Abbiamo bisogno di 8 lezioni ora. Aggiungi un'altra proprietà e avremo bisogno di 16. Questo crescerà come 2 ^ n.

Invece, proviamo a definire un BurgerDecorator che accetta un oggetto Burger:

class BurgerDecorator
  def initialize(burger)
    self.burger = burger
  end
end

class BurgerWithCheese < BurgerDecorator
  def price
    self.burger.price + 15
  end
end

burger = Burger.new
cheese_burger = BurgerWithCheese.new(burger)
cheese_burger.price   # => 65

Nell'esempio sopra, abbiamo creato una classe BurgerDecorator, da cui eredita la classe BurgerWithCheese. Possiamo anche rappresentare la variazione "grande" creando la classe LargeBurger. Ora potremmo definire un grande hamburger con formaggio in fase di esecuzione come:

b = LargeBurger.new(cheese_burger)
b.price  # => 50 + 15 + 20 = 85

Ricordi come l'utilizzo dell'ereditarietà per aggiungere la variante "with fries" comporterebbe l'aggiunta di altre 4 sottoclassi? Con i decoratori, creeremmo solo una nuova classe, BurgerWithFries, per gestire la nuova variante e gestirla in fase di esecuzione. Ogni nuova proprietà avrebbe bisogno di solo più decoratore per coprire tutte le permutazioni.

PS. Questa è la versione breve di un articolo che ho scritto sull'utilizzo del modello Decorator in Ruby , che puoi leggere se desideri scoprire esempi più dettagliati.


2

Decoratore:

  1. Aggiungi comportamento all'oggetto in fase di esecuzione . L'ereditarietà è la chiave per ottenere questa funzionalità, che è sia un vantaggio che uno svantaggio di questo modello.
  2. Migliora il comportamento dell'interfaccia.
  3. Decoratore può essere visto come un composito degenerato con un solo componente. Tuttavia, un decoratore aggiunge ulteriori responsabilità: non è destinato all'aggregazione di oggetti.
  4. La classe Decorator dichiara una relazione di composizione con l'interfaccia LCD (Lowest Class Denominator) e questo membro di dati viene inizializzato nel suo costruttore.
  5. Decorator è progettato per consentire di aggiungere responsabilità agli oggetti senza sottoclasse

Fare riferimento alla creazione di sorgenti all'articolo di per maggiori dettagli.

Decoratore (astratto) : è una classe / interfaccia astratta, che implementa l'interfaccia del componente. Contiene l'interfaccia Component. In assenza di questa classe, sono necessarie molte sottoclassi di ConcreteDecorator per diverse combinazioni. La composizione del componente riduce le sottoclassi non necessarie.

Esempio JDK:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
        char c = (char)bis.read();
        System.out.println("Char: "+c);;
}

Dai un'occhiata alla domanda SE di seguito per il diagramma UML e gli esempi di codice.

Motivo decorativo per IO

Articoli utili:

journaldev

wikipedia

Vero esempio di parola del modello Decoratore: VendingMachineDecorator è stato spiegato @

Quando utilizzare il motivo decorativo?

Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();

beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();

Nell'esempio sopra, il tè o il caffè (bevanda) è stato decorato con zucchero e limone.


2

Il modello Decorator raggiunge un unico obiettivo di aggiungere dinamicamente responsabilità a qualsiasi oggetto .

Il modello I / O Java si basa sul modello del decoratore.

Java IO come motivo decorativo


1

C'è un esempio su Wikipedia sulla decorazione di una finestra con barra di scorrimento:

http://en.wikipedia.org/wiki/Decorator_pattern

Ecco un altro esempio molto "reale" di "Membro del team, responsabile del team e manager", che illustra che il motivo decorativo è insostituibile con una semplice eredità:

https://zishanbilal.wordpress.com/2011/04/28/design-patterns-by-examples-decorator-pattern/


Quel legame di Zishan Bilal è fantastico - il miglior esempio che ho visto
stonedauwg il

1

Qualche tempo fa avevo refactored una base di codice nell'uso del modello Decorator, quindi cercherò di spiegare il caso d'uso.

Supponiamo che abbiamo un set di servizi e in base al fatto che l'utente abbia acquisito la licenza di un determinato servizio, dobbiamo avviare il servizio.

Tutti i servizi hanno un'interfaccia comune

interface Service {
  String serviceId();
  void init() throws Exception;
  void start() throws Exception;
  void stop() throws Exception;
}

Pre refactoring

abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId, LicenseManager licenseManager) {
    // assign instance variables
  }

  @Override
  public void init() throws Exception {
    if (!licenseManager.isLicenseValid(serviceId)) {
       throw new Exception("License not valid for service");
    }
    // Service initialization logic
  }
}

Se osservi attentamente, ServiceSupportdipende da LicenseManager. Ma perché dovrebbe dipendere LicenseManager? E se avessimo bisogno di un servizio in background che non ha bisogno di controllare le informazioni sulla licenza. Nella situazione attuale dovremo in qualche modo allenarci LicenseManagerper tornaretrue per i servizi in background. Questo approccio non mi è sembrato buono. Secondo me il controllo delle licenze e altre logiche erano ortogonali tra loro.

Quindi motivo del decoratore viene in soccorso e qui inizia il refactoring con TDD.

Post refactoring

class LicensedService implements Service {
  private Service service;
  public LicensedService(LicenseManager licenseManager, Service service) {
    this.service = service;
  }

  @Override
  public void init() {
    if (!licenseManager.isLicenseValid(service.serviceId())) {
      throw new Exception("License is invalid for service " + service.serviceId());
    }
    // Delegate init to decorated service
    service.init();
  }

  // override other methods according to requirement
}

// Not concerned with licensing any more :)
abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId) {
    // assign variables
  }

  @Override
  public void init() {
    // Service initialization logic
  }
}

// The services which need license protection can be decorated with a Licensed service
Service aLicensedService = new LicensedService(new Service1("Service1"), licenseManager);
// Services which don't need license can be created without one and there is no need to pass license related information
Service aBackgroundService = new BackgroundService1("BG-1");

Asporto

  • La coesione del codice è migliorata
  • Il collaudo delle unità è diventato più semplice, poiché non è necessario simulare le licenze durante il test di ServiceSupport
  • Non è necessario ignorare le licenze mediante controlli speciali per i servizi in background
  • Corretta divisione delle responsabilità

1

Facciamo un esempio di PubG. I fucili d'assalto funzionano meglio con lo zoom 4x e mentre ci siamo sopra, avremmo anche bisogno di compensatori e soppressori. Ridurrà il rinculo e ridurrà il suono di fuoco e l'eco. Dovremo implementare questa funzione in cui consentiremo ai giocatori di acquistare la loro pistola preferita e i loro accessori. I giocatori possono acquistare la pistola o alcuni degli accessori o tutti gli accessori e verrebbero addebitati di conseguenza.

Vediamo come viene applicato il motivo del decoratore qui:

Supponiamo che qualcuno desideri acquistare SCAR-L con tutti e tre gli accessori sopra menzionati.

  1. Prendi un oggetto di SCAR-L
  2. Decora (o aggiungi) lo SCAR-L con l'oggetto zoom 4x
  3. Decorare lo SCAR-L con un oggetto soppressore
  4. Decorare lo SCAR-L con l'oggetto compressore
  5. Chiama il metodo del costo e consenti a ciascun oggetto delegato di aggiungere il costo utilizzando il metodo del costo degli accessori

Questo porterà a un diagramma di classe come questo:

Motivo decorativo al lavoro

Ora possiamo avere lezioni come questa:

public abstract class Gun {     
    private Double cost;    
    public Double getCost() {           
        return cost;        
       }    
    }

public abstract class GunAccessories extends Gun {  }

public class Scarl extends Gun {    
    public Scarl() {            
        cost = 100;
        }   
     }

public class Suppressor extends GunAccessories {        
    Gun gun;        
    public Suppressor(Gun gun) {            
    cost = 5;           
    this.gun = gun;     
    }               
    public double getCost(){            
        return cost + gun.getCost();
    }
}

public class GunShop{   
    public static void main(String args[]){         
    Gun scarl = new Scarl();                
    scarl = new Supressor(scarl);
    System.out.println("Price is "+scarl.getCost());
    }      
}

Allo stesso modo possiamo aggiungere anche altri accessori e decorare la nostra pistola.

Riferimento:

https://nulpointerexception.com/2019/05/05/a-beginner-guide-to-decorator-pattern/


0

Motivo di disegno del decoratore : questo motivo aiuta a modificare le caratteristiche di un oggetto in fase di esecuzione. Fornisce sapori diversi a un oggetto e offre flessibilità per scegliere quali ingredienti vogliamo usare in quel sapore.

Esempio di vita reale: supponiamo che tu abbia un posto di cabina principale in un volo. Ora puoi scegliere più servizi con il sedile. Ogni comodità ha il suo costo associato. Ora, se un utente sceglie Wifi e cibo premium, verrà addebitato il costo per posto + wifi + cibo premium.

inserisci qui la descrizione dell'immagine

In questo caso il modello di design del decoratore può davvero aiutarci. Visita il link sopra per saperne di più sul modello del decoratore e sull'implementazione di un esempio di vita reale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.