Sencillo e interesante patrón que permite añadir funcionalidades a un objeto en aquellos casos en los que no sea necesario o recomendable hacerlo mediante herencia:
A continuación mostramos uno de los ejemplos clásicos usados para explicarlo: crear una clase que dibuje ventanas básicas, y utilizar el patrón para agregar barras de desplazamiento sólo a algunas de ellas.
Main.java:
package estructurales.decorator.decorator01;
public class Main
{
public static void main(String[] args)
{
IVentana ventana1 = new Ventana();
ventana1.dibujar(50, 70);
System.out.println("-----");
// Dibujar una ventan que tenga la barra de desplazamiento vertical
IVentana ventana2 = new DecoradorDesplazamientoVert( new Ventana() );
ventana2.dibujar(300, 200);
System.out.println("-----");
// Dibujar una ventan que tenga la barra de desplazamiento horizontal
IVentana ventana3 = new DecoradorDesplazamientoHoriz( new Ventana() );
ventana3.dibujar(400, 300);
System.out.println("-----");
// Dibujar una ventan que tenga las barras de desplazamientos horizontal y vertical
IVentana ventana4 = new DecoradorDesplazamientoVert( new DecoradorDesplazamientoHoriz( new Ventana() ) );
ventana4.dibujar(100, 120);
}
}
IVentana.java (IComponente según el diagrama anterior):
package estructurales.decorator.decorator01;
public interface IVentana
{
public void dibujar(int columna, int fila);
}
Ventana.java (ComponenteConcreto según el diagrama anterior):
package estructurales.decorator.decorator01;
public class Ventana implements IVentana
{
public Ventana() {
}
// --------------------------------
@Override
public void dibujar(int col, int fila)
{
System.out.println("Dibujada ventana básica en [" + col + "], [" + fila + "]" );
}
}
DecoradorDesplazamiento.java (Decorador según el diagrama anterior):
package estructurales.decorator.decorator01;
public abstract class DecoradorDesplazamiento implements IVentana
{
protected IVentana v;
// --------------------
public DecoradorDesplazamiento( IVentana v )
{
this.setVentana( v );
}
// --------------------
public IVentana getVentana()
{
return this.v;
}
// --------------------
public void setVentana( IVentana v )
{
this.v = v;
}
// --------------------
@Override
public void dibujar(int col, int fila)
{
this.getVentana().dibujar(col, fila);
}
}
DecoradorDesplazamientoHoriz.java (un DecoradorConcreto según el diagrama anterior):
package estructurales.decorator.decorator01;
public class DecoradorDesplazamientoHoriz extends DecoradorDesplazamiento
{
public DecoradorDesplazamientoHoriz( IVentana v )
{
super( v );
}
// ---------------------------
@Override
public void dibujar(int col, int fila)
{
// Dibujar la ventana
this.getVentana().dibujar(col, fila);
// Agregar barra de desplazamiento
this.dibujarBarraDespHorizontal();
}
// ---------------------------
private void dibujarBarraDespHorizontal()
{
System.out.println("Agregada barra de desplazamiento horizontal");
}
}
DecoradorDesplazamientoVert.java (un DecoradorConcreto según el diagrama anterior):
package estructurales.decorator.decorator01;
public class DecoradorDesplazamientoVert extends DecoradorDesplazamiento
{
public DecoradorDesplazamientoVert( IVentana v )
{
super( v );
}
// ---------------------------
@Override
public void dibujar(int col, int fila)
{
// Dibujar la ventana
this.getVentana().dibujar(col, fila);
// Agregar barra de desplazamiento
this.dibujarBarraDespVertical();
}
// ---------------------------
private void dibujarBarraDespVertical()
{
System.out.println("Agregada barra de desplazamiento vertical");
}
}
Al ejecutarlo obtendríamos como resultado:
EXPLICACIÓN:
- La clase abstracta DecoradorDesplazamiento es la encargada de definir las funcionalidades que se podrán agregar a objetos que (como ella misma) implementan la interface IVentana.
- Contiene además una referencia a otro objeto (asignada en el constructor) de tipo IVentana, y en el método dibujar() que debe implementar simplemente se llama al método del mismo nombre en dicho objeto.
- Los objetos que heredan de DecoradorDesplazamiento llaman al constructor de su clase padre pasándole como parámetro el objeto de tipo IVentana recibido en su propio constructor (para guardar una referencia al mismo y así poder acceder a él en otro momento).
- Cuando se llama al método dibujar() de dichos objetos de tipo DecoradorDesplazamiento se crea la ventana básica, y a continuación a un método propio para agregar la barra de desplazamiento deseada en cada caso.
- Al iniciarse el programa se crea una ventana básica y luego otras que contendrán una o ambas barras de desplazamiento según cada caso (observa cómo en el tercer caso se encadenan los contructores para agregar ambas barras de desplazamiento).