lunes, 5 de mayo de 2008

Decorator

El patrón Decorator responde a la necesidad de añadir dinámicamente funcionalidad a un Objeto. Esto nos permite no tener que crear sucesivas clases que hereden de la primera incorporando la nueva funcionalidad, sino otras que la implementan y se asocian a la primera.

Supongamos que tenemos una clase existente Ventana y queremos añadirle funcionalidad para que muestre un borde alrededor. Podemos crear una subclase VentanaConBorde que herede de Ventana.

Hasta aquí todo bien, pero supongamos que surge la necesidad de crear una ventana que muestre un pequeño botón de ayuda con un signo de interrogación (?) en su parte superior. Entonces tenemos las siguientes opciones:

  • Crear otra subclase de Ventana: VentanaConBotónDeAyuda.

Problema: No cubre la necesidad de tener ventanas con bordes y botón de ayuda a la vez.

  • Crear una subclase de VentanaConBorde: VentanaConBordeYBotonDeAyuda.

Problema: No tenemos una ventana con botón de ayuda y sin borde.

  • Crear clases para todas las combinaciones posibles de funcionalidades.

Problema: Con este ejemplo tendríamos cuatro clases: Ventana, VentanaConBorde, VentanaConBotonDeAyuda y VentanaConBordeYBotonDeAyuda; con tres funcionalidades tendríamos ocho clases y con cuatro, ¡dieciséis!


El patrón Decorator soluciona este problema de una manera mucho más sencilla y extensible.

Se crea a partir de Ventana la subclase abstracta VentanaDecorator y, heredando de ella, BordeDecorator y BotonDeAyudaDecorator. VentanaDecorator encapsula el comportamiento de Ventana y utiliza composición recursiva para que sea posible añadir tantas "capas" de Decorators como se desee. Podemos crear tantos Decorators como queramos heredando de VentanaDecorator

Ejemplo:

abstract class Componente
{
abstract public void Operacion();
}
class ComponenteConcreto extends Componente
{
public void Operacion()
{
System.out.println(
"ConcreteComponent.Operation()");
}
}
abstract class Decorator extends Componente
{
protected Componente componente;
public void SetComponente(Componente component)
{
this.componente = component;
}
public void Operacion()
{
if (componente != null) componente.Operacion();
}
}
class DecoradorConcretoA extends Decorator
{
private String estadoAgregado;
public void Operacion()
{
super.Operacion();
estadoAgregado = "Nuevo estado";
System.out.println("DecoradorConcretoA.Operacion()");
}
}
class DecoradorConcretoB extends Decorator
{
public void Operacion()
{
super.Operacion();
AgregarComportamiento();
System.out.println("DecoradorConcretoB.Operacion()");
}
void AgregarComportamiento()
{
System.out.println("comportamiento añadido B");
}
}
public class Cliente
{
public static void main(String[] args)
{
ComponenteConcreto c = new ComponenteConcreto();
DecoradorConcretoA d1 = new DecoradorConcretoA();
DecoradorConcretoB d2 = new DecoradorConcretoB();
d1.SetComponente(c);
d2.SetComponente(d1);
d2.Operacion();
}
}