Patrones Estructurales: Patrón Decorator

Descripción general

Texto para explicar con un ejemplo que es y cómo se aplica el patrón decorador

[TOC] Tabla de Contenidos


↑↑↑

Objetivo:

Añadir responsabilidades a un objeto de forma dinámica. Los decoradores proporcionan una alternativa flexible a la herencia para extender funcionalidad.

Imagen clases componentes patron decorador

Estructura de clases del patron decorador

Los objetos participantes en este patrón son:

Su filosofía consiste en añadir responsabilidades de forma dinámica al objeto

Como podemos observar en el gráfico superior, la clase [DecoratorAbstrat] y la clase [Parrafo] que es la que queremos decorar, heredan, las dos, de la misma clase [DecoradorComponetAbstract]. Así, cada decorador es capaz de encapsular una instancia de cualquier objeto que herede del componente común, o lo que es lo mismo, puede encapsular o bien un componente concreto o bien, otro decorador.

La encapsulación puede ser iterativa, de modo que un componente concreto puede ser encapsulado por un decorador, que a su vez puede ser encapsulado por otro decorador… y así sucesivamente, añadiendo nueva funcionalidad en cada uno de los pasos. Resumiendo: el patrón Decorador sustituye la herencia por un proceso iterativo de composición.

Patron decorador, idea de encapsulamiento

Forma en la que se encapsulan los objetos

Falta el texto Alt de la imagen

El objeto con el que el objeto cliente interactuará será aquel que se encuentre en la capa más externa (en este caso, DecoratorC), que se encargará de acceder a los objetos contenidos e invocar su funcionalidad, que será devuelta a las capas exteriores.

Consecuencias


↑↑↑

Un ejemplo practico

Con tal de que el patrón quede claro, voy a mostrar un pequeño ejemplo de código en el que utilizo este patrón.

El ejemplo que voy a desarrollar se trata de decorar una clase párrafo,. Una de las clases añade delante y detrás del párrafo unos caracteres "@" y la otra añade unos caracteres "*".

El ejemplo es deliberadamente simple, pero complicándolo solo un poco se pueden diseñar decoradores que, por ejemplo, añaden (o quitan) el salto de línea al final del párrafo, O bien, que pongan detrás de cada punto un salto de línea (si no existe), o bien, poner las marcas de párrafo HTML [<p>…. </p>], y cualquier otra cosa que se te ocurra.


''' <summary>
''' [Patron Decorador] la clase 'Component' 'abstract' 
''' </summary>
Public MustInherit Class DecoradorComponentAbstract

    ' Función que devolverá la clase [ConcreteComponent] que contiene el párrafo que estamos decorando
    ' Se declara como virtual para que pueda sustituirse en las clases derivadas
    Public MustOverride Function OperacionDecorador() As Parrafo

End Class



''' <summary>
'''  [Patron Decorador] la clase 'ConcreteComponent' 
'''  En este caso es una clase que contiene un [párrafo] que queremos decorar
''' </summary>
Public Class Parrafo
    Inherits DecoradorComponentAbstract

    ' contiene el texto original recibido
    Public ReadOnly Property TextoOriginal As String

    ' contendrá el texto final decorado
    Public Property TextoDecorado As String

    ' constructor
    Public Sub New(Texto As String)
        MyBase.New
        TextoOriginal = Texto
        TextoDecorado = Texto
    End Sub

    Public Overrides Function OperacionDecorador() As Parrafo
        ' no hacer nada
        TextoDecorado = TextoOriginal
        Return Me
    End Function

End Class




'-----------------------------------------------------------------
''' <summary>
''' La clase 'Decorator' abstract 
''' </summary>
Public MustInherit Class DecoratorAbstract
    Inherits DecoradorComponentAbstract

    '-----------------------------
    ' Solo sirve a efectos de trazabilidad
    ' No tiene ninguna tarea especifica para la ejecución del código
    Friend Property Descripcion As String = "DecoratorAbstrat"

    '----------------------------------------------------------------------------------
    ' Un decorador o contiene una clase  [ConcreteComponent] --> una clase Párrafo
    ' o contiene una clase [ConcreteDecorator] que hereda de [DecoratorAbstrat]
    ' y tiene que conservar ambos valores diferentes porque hay que hacer cosas diferentes con cada una de ellas
    ' Ejemplo
    '   Dim c As New ConcreteComponent("Hola caracola")
    '   Dim d1 As New ConcreteDecoratorA(c)
    '   Dim d2 As New ConcreteDecoratorB(d1)
    '   Dim d3 As New ConcreteDecoratorC(d2)
    '-------------------------------------------------------------------------
    Protected _componenteConcretoEncapsulado As Parrafo = Nothing
    Protected _decoradorConcretoEncapsulado As DecoratorAbstract = Nothing



    ' Constructor que recibe el la clase [ConcreteComponent]  que encapsulará el decorator
    Public Sub New(componenteEncapsulado As Parrafo)
        _componenteConcretoEncapsulado = componenteEncapsulado
    End Sub


    ' Constructor que recibe el la clase [ConcreteDecorator]  que encapsulará el decorator
    Public Sub New(decoradorEncapsulado As DecoratorAbstract)
        _decoradorConcretoEncapsulado = decoradorEncapsulado
    End Sub


    ' la función Decorador 
    Public Overrides Function OperacionDecorador() As Parrafo

        'Trabajar con el COMPONENTE CONCRETO encapsulado
        If Not (_componenteConcretoEncapsulado Is Nothing) Then
            _componenteConcretoEncapsulado = _componenteConcretoEncapsulado.OperacionDecorador()
        End If

        'Trabajar con el DECORADOR CONCRETO encapsulado
        If Not (_decoradorConcretoEncapsulado Is Nothing) Then
            _componenteConcretoEncapsulado = _decoradorConcretoEncapsulado.OperacionDecorador()
        End If

        'Devuelve un COMPONENTE concreto (En este ejemplo, una clase parrafo)
        Return _componenteConcretoEncapsulado
    End Function

End Class






''' <summary>
''' Una clase 'ConcreteDecorator' 
''' Se encarga de decorar, de poner tres asteriscos delante y detrás del texto
''' </summary>
Class ConcreteDecoratorA
    Inherits DecoratorAbstract

    ' Constructor que recibe el la clase [ConcreteComponent]  que encapsulará el decorator
    Public Sub New(componente As Parrafo)
        MyBase.New(componente)
        MyBase.Descripcion = "ConcreteDecoratorA - componente"
    End Sub


    ' Constructor que recibe el la clase [ConcreteDecorator]  que encapsulará el decorator
    Public Sub New(decoradorEncapsulado As DecoratorAbstract)
        MyBase.New(decoradorEncapsulado)
        MyBase.Descripcion = "ConcreteDecoratorA - Encapsulado"
    End Sub


    Public Overrides Function OperacionDecorador() As Parrafo
        _componenteConcretoEncapsulado = MyBase.OperacionDecorador()
        _componenteConcretoEncapsulado.TextoDecorado = "*** " & _componenteConcretoEncapsulado.TextoDecorado & " ***"
        Return _componenteConcretoEncapsulado
    End Function

End Class







''' <summary>
''' Una clase 'ConcreteDecorator' 
''' Se encarga de decorar, de poner tres 'arrobas' delante y detrás del texto
''' </summary>
Class ConcreteDecoratorB
    Inherits DecoratorAbstract

    ' Constructor que recibe el la clase [ConcreteComponent]  que encapsulará el decorator
    Public Sub New(componente As Parrafo)
        MyBase.New(componente)
        MyBase.Descripcion = "ConcreteDecoratorB - componente"
    End Sub

    ' Constructor que recibe el la clase [ConcreteDecorator]  que encapsulará el decorator
    Public Sub New(concreteDecorator As DecoratorAbstract)
        MyBase.New(concreteDecorator)
        MyBase.Descripcion = "ConcreteDecoratorB - Encapsulado"
    End Sub

    Public Overrides Function OperacionDecorador() As Parrafo
        _componenteConcretoEncapsulado = MyBase.OperacionDecorador()
        _componenteConcretoEncapsulado.TextoDecorado = " @@@ " & _componenteConcretoEncapsulado.TextoDecorado & " @@@ "
        Return _componenteConcretoEncapsulado
    End Function

End Class


↑↑↑

la clase de pruebas

''' <summary>
'''  Clase de pruebas del patron de diseño 'Decorador'
'''  Decorator Design Pattern.
''' </summary>
Class ConsoleStringDecoratorPrueba
    ''' <summary>
    ''' Entry point into console application.
    ''' </summary>
    Public Shared Sub Main()
        ' Create ConcreteComponent and two Decorators
        Dim c As New Parrafo("En un lugar de la Mancha")
        Dim d1 As New ConcreteDecoratorA(c)
        Dim d2 As New ConcreteDecoratorB(d1)

        ' ejecutar los decoradores
        d2.OperacionDecorador()

        'mostrar el resultado
        Console.Write(c.TextoDecorado)
        ' esperar hasta que se pulse una tecla
        Console.ReadKey()
    End Sub
End Class

y una imagen del resultado

Imagen del resultado del ejemplo

Resultado del ejemplo


↑↑↑

A.2.Enlaces

[Para saber mas]
[Grupo de documentos]
[Documento Index]
[Documento Start]
[Imprimir el Documento]
© 1997 - - La Güeb de Joaquín
Joaquín Medina Serrano
Ésta página es española

Codificación
Fecha de creación
Última actualización
[HTML5 Desarrollado usando CSS3]