Comprenda el "patrón de decorador" con un ejemplo del mundo real


167

Estaba estudiando el patrón de decorador como se documenta en GOF .

Por favor, ayúdame a entender el Patrón Decorador . ¿Podría alguien dar un ejemplo de caso de uso de dónde esto es útil en el mundo real?


8
Puede encontrar aquí algunos ejemplos del mundo real en la API de Java: stackoverflow.com/questions/1673841/…
BalusC

Un artículo que muestra los beneficios del patrón decorador con ejemplos simples: dzone.com/articles/is-inheritance-dead
nbilal

Respuestas:


226

El patrón de decorador logra un único objetivo de agregar dinámicamente responsabilidades a cualquier objeto.

Considere un caso de una pizzería. En la pizzería venderán pocas variedades de pizza y también proporcionarán ingredientes en el menú. Ahora imagine una situación en la que la pizzería tiene que proporcionar precios para cada combinación de pizza y cobertura. Incluso si hay cuatro pizzas básicas y 8 coberturas diferentes, la aplicación se volvería loca manteniendo todas estas combinaciones concretas de pizzas y coberturas.

Aquí viene el patrón decorador.

Según el patrón del decorador, implementará coberturas como decoradores y las pizzas serán decoradas por los decoradores de esas coberturas. Prácticamente cada cliente querría ingredientes de su deseo y el monto final de la factura estará compuesto por las pizzas base y los ingredientes adicionales ordenados. Cada decorador de topping sabría acerca de las pizzas que está decorando y su precio. El método GetPrice () del objeto Topping devolvería el precio acumulado tanto de la pizza como del topping.

EDITAR

Aquí hay un ejemplo de código de explicación anterior.

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
No me gusta este patrón ni un poco. Quizás es el ejemplo sin embargo. El principal problema que tengo con él en términos de OOD es que un topping no es una pizza . Preguntarle por el precio de la pizza a la que se aplica simplemente no me sienta bien. Sin embargo, es un ejemplo muy atento y detallado, así que no pretendo golpearte por eso.
Tom W

39
@TomW Creo que parte del problema son los nombres. Todas las clases "Topping" deben llamarse "PizzaWith <Topping>". Por ejemplo, "PizzaWithMushrooms".
Josh Noe

2
En mi opinión, los decoradores se usan mejor de la manera más plana posible. Con eso me refiero a la menor cantidad posible de "decoradores que envuelven decoradores". Entonces, tal vez este ejemplo no sea el más adecuado. Pero es bastante completo, lo cual es bueno.
thekingoftruth

17
Desde otra perspectiva, esto ni siquiera se acerca al "mundo real". En el mundo real, no debe volver a compilar cada vez que necesite agregar un nuevo topping en el menú (o cambiar el precio). Los ingredientes se almacenan (generalmente) en la base de datos y, por lo tanto, hacen que el ejemplo anterior sea inútil.
Stelios Adamantidis

44
^ Esto. Creo que esto es lo que me ha estado molestando todo el tiempo mientras estudiaba este patrón. Si fuera una empresa de software y escribiera software de pizzería, no me gustaría tener que volver a compilar y reenviar cada vez. Me gustaría agregar una fila en una tabla en el back-end o algo que fácilmente se encargaría de sus requisitos. Bien dicho, @Stelios Adamantidis. Supongo que la mayor fortaleza de los patrones sería modificar las clases de terceros en ese momento.
Canucklesandwich

33

Este es un ejemplo simple de agregar dinámicamente un nuevo comportamiento a un objeto existente, o el patrón Decorator. Debido a la naturaleza de los lenguajes dinámicos como Javascript, este patrón se convierte en parte del lenguaje en sí.

// 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');


Simple y preciso! Gran ejemplo!
nagendra547

1
No creo que el concepto de Patrón Decorador sea aplicable aquí. En realidad no es un patrón en absoluto! Sí, está agregando un nuevo método en tiempo de ejecución. Y probablemente dentro de uno switcho un simple if, podría afirmar que este es un gran ejemplo de agregar dinámicamente el comportamiento a una clase. PERO, necesitamos al menos dos clases para definir un decorador y objetos decorados en este patrón.
Iman

1
@Zich Entiendo que no hay decorador en mi ejemplo, pero eso se soluciona fácilmente agregando una función que sirve como decorador. Pero hay un objeto decorado en mi ejemplo. ¿El patrón dice en alguna parte que necesitas dos clases específicamente?
Anurag

18

Vale la pena señalar que el modelo de E / S de Java se basa en el patrón decorador. La colocación en capas de este lector encima de ese lector encima de ... es un ejemplo de decorador del mundo real.


¿Hay otros ejemplos en API públicas reales? Este es el único que conozco.
Josiah Yoder

Parece que todas las funciones de envoltura en la naturaleza tienen algún tipo de patrón de decorador incorporado, ¿es eso lo que creo que es?
Harvey Lin

Buen ejemplo !!
nagendra547

8

Ejemplo: escenario: supongamos que está escribiendo un módulo de cifrado. Este cifrado puede cifrar el archivo sin cifrar utilizando DES - Estándar de cifrado de datos. Del mismo modo, en un sistema puede tener el cifrado como AES: estándar de cifrado avanzado. Además, puede tener la combinación de cifrado: primero DES, luego AES. O puede tener primero AES, luego DES.

Discusión: ¿Cómo atenderá esta situación? No puede seguir creando el objeto de tales combinaciones, por ejemplo, AES y DES, un total de 4 combinaciones. Por lo tanto, debe tener 4 objetos individuales. Esto se volverá complejo a medida que aumente el tipo de cifrado.

Solución: siga acumulando la pila, combinaciones según la necesidad, en tiempo de ejecución. Otra ventaja de este enfoque de pila es que puede desenrollarlo fácilmente.

Aquí está la solución: en C ++.

En primer lugar, necesita una clase base, una unidad fundamental de la pila. Puedes pensar como la base de la pila. En este ejemplo, es un archivo claro. Sigamos siempre el polimorfismo. Primero haga una clase de interfaz de esta unidad fundamental. De esta manera, puede implementarlo como desee. Además, no necesita pensar en la dependencia al incluir esta unidad fundamental.

Aquí está la clase de interfaz:

class IclearData
{
public:

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

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

Ahora, implemente esta clase de interfaz:

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;
    }

};

Ahora, hagamos una clase abstracta de decorador, que se puede extender para crear cualquier tipo de sabores, aquí el sabor es el tipo de cifrado. Esta clase abstracta de decorador está relacionada con la clase base. Por lo tanto, el decorador "es un" tipo de clase de interfaz. Por lo tanto, debe usar la herencia.

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;
}

Ahora, hagamos una clase de decorador concreto - Tipo de cifrado - 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;
    }

};

Ahora, digamos que el tipo de decorador es DES -

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

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;
    }

};

Hagamos un código de cliente para usar esta clase de decorador:

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;
}

Verá los siguientes resultados:

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

Aquí está el diagrama UML - Representación de clase del mismo. En caso de que desee omitir el código y centrarse en el aspecto del diseño.

ingrese la descripción de la imagen aquí


1
¿No es el ejemplo más adecuado para strategy pattern?
exexzian

@exexzian Sí, mis alumnos constantemente me sugieren una lista de estrategias para este tipo de problema, y ​​también me parece la solución más limpia.
Josiah Yoder

No, con el patrón de estrategia no puede combinar los métodos de cifrado. Por lo tanto, tendría que crear una clase de estrategia para cada combinación posible.
deetz

4

El patrón de decorador lo ayuda a cambiar o configurar una funcionalidad de su objeto al encadenarlo con otras subclases similares de este objeto.

El mejor ejemplo sería las clases InputStream y OutputStream en el paquete 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.

En este caso, la cadena de llamada comienza en ObjectOutputStream, luego sube hasta la clase File, luego la clase File devuelve el valor, luego las otras tres subclases los suman y finalmente, el valor del método ObjectOutputStream lo devuelve, es ¿que correcto?
Harvey Lin

3

Qué es el patrón de diseño de decorador en Java.

La definición formal del patrón Decorator del libro GoF (Patrones de diseño: Elementos de software orientado a objetos reutilizables, 1995, Pearson Education, Inc. Publicación como Pearson Addison Wesley) dice que puede,

"Asigne responsabilidades adicionales a un objeto dinámicamente. Los decoradores proporcionan una alternativa flexible a la subclasificación para ampliar la funcionalidad".

Digamos que tenemos una pizza y queremos decorarla con ingredientes como pollo Masala, cebolla y queso mozzarella. Veamos cómo implementarlo en Java ...

Programa para demostrar cómo implementar Decorator Design Pattern en 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

He usado el patrón Decorator ampliamente en mi trabajo. Hice una publicación en mi blog sobre cómo usarlo con el registro.


No me gusta que hayas lanzado un enlace como respuesta. Pero tu artículo de blog es tan útil que tuve que votar :). Ahora realmente lo entiendo. Todos vienen con pizza, y tú con un ejemplo perfecto.
Niklas Raab

2

El patrón decorador le permite agregar dinámicamente comportamiento a los objetos.

Tomemos un ejemplo en el que necesita crear una aplicación que calcule el precio de diferentes tipos de hamburguesas. Debe manejar diferentes variaciones de hamburguesas, como "grande" o "con queso", cada una de las cuales tiene un precio relativo a la hamburguesa básica. Por ejemplo, agregue $ 10 por hamburguesa con queso, agregue $ 15 adicionales por hamburguesa grande, etc.

En este caso, podría verse tentado a crear subclases para manejarlos. Podríamos expresar esto en Ruby como:

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

En el ejemplo anterior, la clase BurgerWithCheese hereda de Burger y anula el método de precio para agregar $ 15 al precio definido en la superclase. También crearía una clase LargeBurger y definiría el precio relativo a Burger. Pero también debe definir una nueva clase para la combinación de "grande" y "con queso".

¿Qué sucede si necesitamos servir "hamburguesa con papas fritas"? Ya tenemos 4 clases para manejar esas combinaciones, y necesitaremos agregar 4 más para manejar todas las combinaciones de las 3 propiedades: "grande", "con queso" y "con papas fritas". Necesitamos 8 clases ahora. Agregue otra propiedad y necesitaremos 16. Esto crecerá como 2 ^ n.

En su lugar, intentemos definir un BurgerDecorator que tome un objeto 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

En el ejemplo anterior, hemos creado una clase BurgerDecorator, de la cual hereda la clase BurgerWithCheese. También podemos representar la variación "grande" creando la clase LargeBurger. Ahora podríamos definir una hamburguesa grande con queso en tiempo de ejecución como:

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

¿Recuerda cómo usar la herencia para agregar la variación "con papas fritas" implicaría agregar 4 subclases más? Con los decoradores, solo crearíamos una nueva clase, BurgerWithFries, para manejar la nueva variación y manejar esto en tiempo de ejecución. Cada nueva propiedad necesitaría simplemente más decorador para cubrir todas las permutaciones.

PD. Esta es la versión corta de un artículo que escribí sobre el uso del Patrón Decorador en Ruby , que puede leer si desea obtener ejemplos más detallados.


2

Decorador:

  1. Agregue comportamiento al objeto en tiempo de ejecución . La herencia es la clave para lograr esta funcionalidad, que es tanto una ventaja como una desventaja de este patrón.
  2. Mejora el comportamiento de la interfaz.
  3. El decorador se puede ver como un compuesto degenerado con un solo componente. Sin embargo, un Decorador agrega responsabilidades adicionales: no está destinado a la agregación de objetos.
  4. La clase Decorator declara una relación de composición con la interfaz LCD (Denominador de clase más baja), y este miembro de datos se inicializa en su constructor.
  5. Decorator está diseñado para permitirle agregar responsabilidades a los objetos sin subclasificar

Consulte la creación de fuentes artículo de para obtener más detalles.

Decorador (Resumen) : es una clase / interfaz abstracta, que implementa la interfaz del componente. Contiene interfaz de componentes. En ausencia de esta clase, necesita muchas subclases de ConcreteDecorators para diferentes combinaciones. La composición del componente reduce las subclases innecesarias.

Ejemplo de 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);;
}

Eche un vistazo a la siguiente pregunta SE para ver ejemplos de diagramas y códigos UML.

Patrón de decorador para IO

Artículos utiles:

journaldev

wikipedia

Ejemplo de palabra real del patrón Decorator: VendingMachineDecorator se ha explicado @

¿Cuándo usar el patrón decorador?

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

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

En el ejemplo anterior, el té o el café (bebida) ha sido decorado con azúcar y limón.


2

El patrón de decorador logra un único objetivo de agregar dinámicamente responsabilidades a cualquier objeto .

Java I / O Model se basa en el patrón decorador.

Java IO como patrón decorador


1

Hay un ejemplo en Wikipedia sobre la decoración de una ventana con barra de desplazamiento:

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

Aquí hay otro ejemplo muy "real" de "miembro del equipo, líder del equipo y gerente", que ilustra que el patrón del decorador es insustituible con una herencia simple:

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


Ese enlace de Zishan Bilal es genial - el mejor ejemplo que he visto
stonedauwg

1

Hace algún tiempo había refactorizado una base de código para usar el patrón Decorator, así que intentaré explicar el caso de uso.

Supongamos que tenemos un conjunto de servicios y, en función de si el usuario ha adquirido una licencia de un servicio en particular, necesitamos iniciar el servicio.

Todos los servicios tienen una interfaz común.

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

Pre Refactorización

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
  }
}

Si observa con cuidado, ServiceSupportdepende de LicenseManager. Pero, ¿por qué debería ser dependiente LicenseManager? ¿Qué sucede si necesitáramos un servicio en segundo plano que no necesita verificar la información de la licencia? En la situación actual tendremos que entrenar de alguna manera LicenseManagerpara volvertrue a los servicios de fondo. Este enfoque no me pareció bien. Según mi verificación de licencia y otra lógica eran ortogonales entre sí.

Entonces, Decorator Pattern viene al rescate y aquí comienza a refactorizar con TDD.

Post refactorización

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");

Comida para llevar

  • La cohesión del código mejoró
  • Las pruebas unitarias se volvieron más fáciles, ya que no tiene que burlarse de las licencias al probar ServiceSupport
  • No es necesario omitir la licencia mediante ninguna verificación especial para servicios en segundo plano.
  • División adecuada de responsabilidades

1

Tomemos ejemplo de PubG. Los rifles de asalto funcionan mejor con un zoom de 4x y mientras estamos en él, también necesitaríamos compensador y supresor. Reducirá el retroceso y el sonido de disparo, así como el eco. Tendremos que implementar esta función donde permitiremos a los jugadores comprar su arma favorita y sus accesorios. Los jugadores pueden comprar el arma o algunos de los accesorios o todos los accesorios y se les cobrará en consecuencia.

Veamos cómo se aplica el patrón decorador aquí:

Supongamos que alguien quiere comprar SCAR-L con los tres accesorios mencionados anteriormente.

  1. Toma un objeto de SCAR-L
  2. Decora (o agrega) el SCAR-L con un objeto de zoom 4x
  3. Decora el SCAR-L con objeto supresor
  4. Decora el SCAR-L con objeto compresor
  5. Llame al método de costo y deje que cada objeto delegue para agregar el costo usando el método de costo de accesorios

Esto llevará a un diagrama de clase como este:

Patrón de decorador en el trabajo

Ahora, podemos tener clases como esta:

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());
    }      
}

También podemos agregar otros accesorios y decorar nuestra pistola.

Referencia:

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


0

Patrón de diseño de decorador : este patrón ayuda a modificar las características de un objeto en tiempo de ejecución. Proporciona diferentes sabores a un objeto y brinda flexibilidad para elegir qué ingredientes queremos usar en ese sabor.

Ejemplo de la vida real: Digamos que tiene un asiento de cabina principal en un vuelo. Ahora puede elegir múltiples comodidades con el asiento. Cada amenidad tiene su propio costo asociado. Ahora, si un usuario elige Wifi y comida premium, se le cobrará por asiento + wifi + comida premium.

ingrese la descripción de la imagen aquí

En este caso, el patrón de diseño del decorador realmente puede ayudarnos. Visite el enlace anterior para comprender más sobre el patrón decorador y la implementación de un ejemplo de la vida real.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.