java - patron - ¿Por qué necesitamos el decorador en el patrón de diseño del decorador?
patron proxy (4)
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 funcione, necesitaremos crear una clase de decorador, por ejemplo ADecorator
, que mantendrá una referencia a una instancia A
, y todos los demás decoradores extenderán esto para agregar funcionalidad.
No entiendo por qué tenemos que crear una clase de decorador, en lugar de usar una instancia A
?
No puedo explicarlo mejor que el artículo de Wikipedia .
En algunos idiomas (como Ruby o JavaScript), puede agregar nuevas funciones a una instancia A. Noté que tu pregunta está etiquetada como Java, así que supongo que estás preguntando por qué no puedes hacer esto en Java. La razón es que Java está tipado estáticamente. 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 A un método que A no define, entonces este nuevo método debe definirse en una clase diferente.
Por cierto, si recién estás comenzando con patrones, el libro de Patrones de Diseño de Head First es fenomenal . Realmente hace que los conceptos sean simples de digerir, y se asegura de contrastar y comparar patrones similares de una manera que es ridículamente fácil de entender.
El patrón de decorador se usa para agregar capacidades a los objetos dinámicamente (es decir, en tiempo de ejecución). Normalmente, el objeto tendrá sus capacidades corregidas cuando escriba la clase. Pero un punto importante es que la funcionalidad del objeto se extiende de forma transparente para el cliente del objeto porque implementa la misma interfaz que el objeto original que delega la responsabilidad del objeto decorado.
El patrón de decorador funciona en escenarios donde hay muchas funciones opcionales que un objeto puede tener. Sin el patrón de decorador, deberá crear una clase diferente para cada configuración de opción de objeto. Un ejemplo que es bastante útil proviene del libro de 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;
}
A continuación, el cliente puede agregar crema que cuesta 0,35 por lo 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 es posible que desee Mocha con crema o Mocha sin crema. Entonces creas las clases CoffeeMochaCream y CoffeeMocha. Entonces un cliente quiere crema doble para que crees una clase de CoffeeCreamCream ... etc. Lo que terminas con explosión de clase. Disculpe el pobre 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 puedes crear una clase concreta de Café que amplíe Artículo:
public class Coffee extends Item{
public double cost(){
return 3.45;
}
}
Luego, crea un CoffeeDecorator que extiende la misma interfaz y contiene un artículo.
public abstract class CoffeeDecorator extends Item{
private Item item;
...
}
Luego puedes crear decoradores concretos para cada opción:
public class Mocha extends CoffeeDecorator{
public double cost(){
return item.cost() + 0.5;
}
}
¿Se da cuenta de que al decorador no le importa qué tipo de objeto está envolviendo siempre que sea un artículo? 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 un gran número de configuraciones con estas pocas clases: por ej.
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í.