Patrones de diseño - Decorator

El patrón Decorator (Decorador, también llamado Wrapper o Envoltorio) proporciona una forma de añadir funcionalidad a un objeto de forma dinámica. Perteneciente al grupo de patrones estructurales, este decorator o envoltorio tiene los mismos métodos que el objeto principal al que "envuelve" y le delega a este todas las solicitudes que recibe, pero tiene la capacidad de alterar el resultado modificando de esta forma la respuesta. 

Necesidad

En algunas ocasiones tenemos la necesidad de añadir ciertas responsabilidades a determinados objetos de una clase concreta, pero no a todos ellos. La idea es poder añadir funcionalidad a ciertos objetos, por lo que creamos un decorator o envoltorio que delega todas las solicitudes que recibe al objeto principal modificando el resultado.

El ejemplo clásico es una interfaz gráfica en la que a algunos de sus objetos les podemos añadir un borde. No todos los objetos de la clase tienen borde y éste solo complementa al objeto.

El envoltorio implementa la misma interfaz que el objeto al que "envuelve" por lo que, desde la perspectiva del cliente, estos objetos son idénticos. Haciendo que el envoltorio acepte cualquier objeto que implemente esta interfaz nos permite añadir más envoltorios con más funciones de forma combinada.

Tenemos los siguientes participantes en este patrón:

  • Componente: Se trata de la interfaz que define los objetos a los que se le puede añadir la responsabilidad de forma dinámica
  • ComponenteConcreto: Define el objeto que implementa la interfaz Componente
  • Decorator: Define una interfaz que se ajusta a la interfaz Componente y mantiene una referencia a un objeto que implementa la interfaz Componente
  • DecoratorConcreto: Añade responsabilidad al Componente

Implementación

Para el ejemplo tenemos una tienda de bicicletas y patinetes donde algunos de ellos se pueden alquilar. Los objetos BicicletaElectrica y PatineteElectrico se crean siguiendo una interfaz ArticulosElectricos y algunos de ellos tendrán la posibilidad de ser alquilados, añadiéndoles una funcionalidad extra usando un patrón decorator.

En nuestro ejemplo tendremos las siguientes correspondencias con los elementos del patrón:

  • Componente: ArticulosElectricos
  • ComponenteConcreto: BicicletaElectrica y PatineteElectrico
  • Decorator: Decorador
  • DecoratorConcreto: Alquilable

La representación de nuestras clases sería así:

Patrón Decorator

Código en Vala

Primero tenemos la clase abstracta ArticulosElectricos de la que heredarán dos de los participantes que hemos visto componen este patrón: Componente y Decorator:

ArticulosElectricos.vala
abstract class ArticulosElectricos 
{ 
    protected int numUnidades { get; set; default=0; } 
     
    public abstract void Mostrar (); 
} 

Las siguientes dos clases (corresponden al participante ComponenteConcreto del patrón) heredan de la clase anterior:

BicicletaElectrica.vala
class BicicletaElectrica : ArticulosElectricos 
{ 
    private string modelo { get; set; default=""; } 
    private string color { get; set; default=""; } 
     
    public BicicletaElectrica (string modelo, string color, int numUnidades) 
    { 
        this._modelo = modelo; 
        this._color = color; 
        this.numUnidades = numUnidades; 
    } 
     
    public override void Mostrar () 
    { 
        print ("\n------------------------------\n"); 
        print ("Bicicleta Eléctrica: %d unidades\n", numUnidades); 
        print ("Modelo: %s Color: %s\n", _modelo, _color); 
        print ("------------------------------\n"); 
    } 
} 

PatineteElectrico.vala
class PatineteElectrico : ArticulosElectricos 
{ 
    private string modelo { get; set; default=""; } 
    private string color { get; set; default=""; } 
    private string tamano { get; set; default=""; } 
     
    public PatineteElectrico (string modelo, string color,  
                string tamano, int numUnidades) 
    { 
        this._modelo = modelo; 
        this._color = color; 
        this._tamano = tamano; 
        this.numUnidades = numUnidades; 
    } 
     
    public override void Mostrar () 
    { 
        print ("\n------------------------------\n"); 
        print ("Patinete Eléctrico: %d unidades\n", numUnidades); 
        print ("Modelo: %s Color: %s Tamaño: %s\n", _modelo, _color, _tamano); 
        print ("------------------------------\n"); 
    } 
} 

Luego tenemos nuestro Decorator:

Decorador.vala
abstract class Decorador : ArticulosElectricos 
{ 
    protected ArticulosElectricos articuloElectrico; 
     
    protected Decorador (ArticulosElectricos articuloElectrico) 
    { 
        this.articuloElectrico = articuloElectrico; 
    } 
     
    public override void Mostrar () 
    { 
        this.articuloElectrico.Mostrar (); 
    } 
} 

Y Alquilable (DecoratorConcreto) que hereda de la anterior y añade la capacidad de poder ser alquilados a los objetos de tipo ArticulosElectricos:

Alquilable.vala
using Gee; 
 
class Alquilable: Decorador 
{ 
    protected ArrayList<string> clientes = new ArrayList<string>(); 
     
    public Alquilable (ArticulosElectricos articuloElectrico) 
    { 
        base (articuloElectrico); 
    } 
     
    public void AlquilarEquipo (string nombre) 
    { 
        clientes.add (nombre); 
        articuloElectrico.numUnidades--; 
    } 
     
    public void DevolverEquipo (string nombre) 
    { 
        clientes.remove (nombre); 
        articuloElectrico.numUnidades++; 
    } 
     
    public override void Mostrar () 
    { 
        base.Mostrar (); 
        print ("Alquiladas: "); 
        foreach (string cliente in clientes) 
        { 
            print (@"[$cliente]"); 
        } 
        print ("\n------------------------------\n"); 
    } 
} 

Nos queda el cliente que hace uso del patrón:

UsoPatronDecorator.vala
class UsoPatronDecorator : GLib.Object 
{ 
    public static int main (string[] args) 
    { 
        Intl.setlocale (ALL); 
         
        BicicletaElectrica bicicleta = new BicicletaElectrica ("Junior", "Roja", 15); 
        PatineteElectrico patinete = new PatineteElectrico ("Rayo", "Plata", "Mediano", 25); 
         
        bicicleta.Mostrar (); 
        patinete.Mostrar (); 
         
        Alquilable alquilarBici = new Alquilable (bicicleta); 
        alquilarBici.AlquilarEquipo ("Carla"); 
        alquilarBici.AlquilarEquipo ("Julia"); 
        alquilarBici.AlquilarEquipo ("Cristina"); 
        alquilarBici.DevolverEquipo ("Julia");  
          
        alquilarBici.Mostrar (); 
         
        return 0; 
         
    } 
}  

Construimos y ejecutamos el programa:

❯ valac --pkg=gee-0.8 Alquilable.vala Decorador.vala UsoPatronDecorator.vala ArticulosElectricos.vala BicicletaElectrica.vala PatineteElectrico.vala -o UsoPatronDecorator
❯ ./UsoPatronDecorator

------------------------------
Bicicleta Eléctrica: 15 unidades
Modelo: Junior Color: Roja
------------------------------

------------------------------
Patinete Eléctrico: 25 unidades
Modelo: Rayo Color: Plata Tamaño: Mediano
------------------------------

------------------------------
Bicicleta Eléctrica: 13 unidades
Modelo: Junior Color: Roja
------------------------------
Alquiladas: [Carla][Cristina]
------------------------------

 

Indice de Patrones

(0 votos)
Etiquetado como :

Deja un comentario

Asegúrese de introducir toda la información requerida, indicada por un asterisco (*). No se permite código HTML.