El patrón Decorator
Descripción
El objetivo del patrón Decorator es agregar dinámicamente funcionalidades suplementarias a un objeto. Esta agregación de funcionalidades no modifica la interfaz del objeto y es transparente de cara a los clientes.
El patrón Decorator constituye una alternativa respecto a la creación de una subclase para enriquecer el objeto.
Ejemplo
El sistema de venta de vehículos dispone de una clase VistaCatálogo que muestra, bajo el formato de un catálogo electrónico, los vehículos disponibles en una página Web.
Queremos a continuación visualizar datos suplementarios para los vehículos "de alta gama", a saber la información técnica ligada al modelo. Para agregar esta funcionalidad, podemos crear una subclase de visualización específica para los vehículos "de alta gama". Así mismo, queremos mostrar el logotipo de la marca en los vehículos "de gamas media y alta". Conviene crear una nueva subclase para estos vehículos, superclase de la clase de vehículos "de alta gama", lo cual se vuelve rápidamente complejo.
Es fácil darse cuenta de que la herencia no está adaptada a lo que se demanda por dos motivos:
-
La herencia es una herramienta demasiado potente para agregar esta funcionalidad,
-
La herencia es un mecanismo estático.
El patrón Decorator proporciona otro enfoque que consiste en agregar un nuevo objeto llamado decorador que se sustituye por el objeto inicial y que lo referencia. Este decorador posee la misma interfaz lo cual vuelve a la sustitución transparente de cara a los clientes. En nuestro caso, el método visualiza lo intercepta el decorador que solicita al objeto inicial su visualización...
Estructura
1. Diagrama de clases
La figura 3-5.4 detalla la estructura genérica del patrón.
Figura 3-5.4 - Estructura del patrón Decorator
2. Participantes
Los participantes del patrón son los siguientes:
-
ComponenteAbstracto (ComponenteGráficoVehículo) es la interfaz común al componente y a los decoradores.
-
ComponenteConcreto (VistaVehículo) es el objeto inicial al que se deben agregar las nuevas funcionalidades.
-
Decorador es una clase abstracta que guarda una referencia hacia el componente.
-
DecoradorConcretoA y DecoradorConcretoB (ModeloDecorador y MarcaDecorador) son subclases concretas de Decorador que tienen como objetivo implementar las funcionalidades agregadas al componente.
3. Colaboraciones
El decorador se sustituye por el componente. Cuando recibe un mensaje destinado a este último, lo redirige al componente realizando operaciones previas o posteriores a esta redirección.
Dominios de aplicación
El patrón Decorator puede utilizarse en los siguientes dominios:
-
Un sistema agrega dinámicamente funcionalidades a un objeto, sin modificar su interfaz, es decir sin que los clientes de este objeto tengan que verse modificados.
-
Un sistema gestiona funcionalidades que pueden eliminarse dinámicamente.
-
El uso de la herencia para extender los objetos no es práctico, lo cual puede ocurrir cuando su jerarquía ya es de por sí compleja.
Ejemplo en C#
Presentamos a continuación el código fuente en C# del ejemplo, comenzando por la interfaz ComponenteGraficoVehiculo.
public interface ComponenteGraficoVehiculo
{
void visualiza();
}
La clase VistaVehiculo implementa el método visualiza de la interfaz ComponenteGraficoVehiculo.
using System;
public class VistaVehiculo : ComponenteGraficoVehiculo
{
public void visualiza()
{
Console.WriteLine("Visualización del vehículo");
}
}
La clase Decorador implementa a su vez el método visualiza delegando la llamada. Tiene un atributo que contiene una referencia hacia un componente. Este último se pasa como parámetro al constructor de Decorador.
public abstract class Decorador :
ComponenteGraficoVehiculo
{
protected ComponenteGraficoVehiculo componente;
public Decorador(ComponenteGraficoVehiculo componente)
{
this.componente = componente;
}
public virtual void visualiza()
{
componente.visualiza(); ...