Pregunta

Suponiendo que tengo una clase llamada A , y quiero usar el patrón de diseño del decorador. Corrígeme si me equivoco, pero para que eso funcione, necesitaremos crear una clase de decorador, digamos ADecorator , que contendrá una referencia a una instancia de A , y todos los demás decoradores lo ampliarán para agregar funcionalidad.

No entiendo por qué tenemos que crear una clase de decorador, en lugar de usar una instancia A ?

¿Fue útil?

Solución

El patrón decorador se usa para agregar capacidades a los objetos dinámicamente (es decir, en tiempo de ejecución). Normalmente el objeto tendrá sus capacidades fijas cuando escriba la clase. Pero un punto importante es que la funcionalidad del objeto se extiende de manera transparente para el cliente del objeto porque implementa la misma interfaz que el objeto original delega responsabilidad al objeto decorado.

El patrón decorador funciona en escenarios donde hay muchas funciones opcionales que puede tener un objeto. Sin el patrón decorador, deberá crear una clase diferente para cada configuración de opción de objeto. Un ejemplo que es bastante útil proviene del libro Head First Design Patterns de O'Reilly. Utiliza un ejemplo de cafetería que suena como StarBucks.

Entonces tienes el café básico con un método como el costo.

public double cost(){
     return 3.45;
}

Entonces el cliente puede agregar crema que cuesta 0.35, así que ahora crea una clase CoffeeCream con el método de costo:

public double cost(){
    return 3.80;
}

Entonces el cliente puede querer Mocha que cuesta 0.5, y puede querer Mocha con Crema o Mocha sin Crema. Entonces creas clases CoffeeMochaCream y CoffeeMocha. Entonces, un cliente quiere crema doble para que crees una clase CoffeeCreamCream ... etc. Lo que terminas es una explosión de clase. Por favor, disculpe el mal ejemplo utilizado. Es un poco tarde y sé que es trivial, pero expresa el punto.

En su lugar, puede crear una clase abstracta de artículo con un método de costo abstracto:

public abstract class Item{
    public abstract double cost();
}

Y puede crear una clase de café concreta que extienda el elemento:

public class Coffee extends Item{
    public double cost(){
       return 3.45;
    }
}

Luego crea un CoffeeDecorator que extiende la misma interfaz y contiene un elemento.

public abstract class CoffeeDecorator extends Item{
     private Item item;
     ...
}

Luego puede crear decoradores concretos para cada opción:

public class Mocha extends CoffeeDecorator{

   public double cost(){
     return item.cost() + 0.5;
   }

}

Observe que al decorador no le importa qué tipo de objeto está envolviendo siempre que sea un elemento. Utiliza el costo () del objeto del artículo y simplemente agrega su propio costo.

public class Cream extends CoffeeDecorator{

   public double cost(){
     return item.cost() + 0.35;
   }

}

Ahora es posible para una gran cantidad de configuraciones con estas pocas clases: por ejemplo,

 Item drink = new Cream(new Mocha(new Coffee))); //Mocha with cream

o

 Item drink = new Cream(new Mocha(new Cream(new Coffee))));//Mocha with double cream

Y así sucesivamente.

Otros consejos

No puedo explicarlo mejor que el wikipedia artículo.

Por cierto, si recién estás comenzando con patrones, el libro Head First Design Patterns es fenomenal . Realmente hace que los conceptos sean fáciles de digerir, y se asegura de contrastar y comparar patrones similares de una manera ridículamente fácil de entender.

En algunos lenguajes (como Ruby o JavaScript) podría agregar una nueva funcionalidad a una instancia A. Noté que su pregunta está etiquetada como Java, por lo que supongo que está preguntando por qué no puede hacer esto en Java. La razón es que Java está estáticamente tipado. Una instancia A solo puede tener los métodos que la clase A define o hereda. Por lo tanto, si desea, en tiempo de ejecución, dar a una instancia de A un método que A no defina, entonces este nuevo método debe definirse en una clase diferente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top