1. ¿Qué es el Patrón Decorador?
El patrón decorador es un patrón de diseño estructural que permite agregar características adicionales a un objeto dinámicamente sin modificar el código del objeto. Logra esto envolviendo el objeto en una clase decoradora, proporcionando la capacidad de agregar, modificar o mejorar el comportamiento del objeto en tiempo de ejecución.
2. Características y Ventajas del Patrón Decorador
Las características y ventajas del patrón decorador incluyen:
- Extender dinámicamente la funcionalidad de un objeto sin modificar su código.
- Cumplimiento con el Principio Abierto-Cerrado, permitiendo la adición y eliminación dinámica de decoradores.
- Capacidad de combinar múltiples decoradores para lograr extensiones de funcionalidad anidadas.
- Independencia de los decoradores de la forma en que se decora el objeto, permitiendo realizar cambios de forma independiente.
3. Ejemplos de Aplicaciones Prácticas del Patrón Decorador
El patrón decorador tiene muchas aplicaciones prácticas en el desarrollo de software, tales como:
- Agregar dinámicamente funcionalidad de registro
- Agregar dinámicamente funcionalidad de almacenamiento en caché
- Validación dinámica de datos
4. Implementación del Patrón Decorador en Golang
4.1. Diagrama de Clase UML
4.2. Introducción del Ejemplo
En el ejemplo, tenemos una interfaz Component y una clase ConcreteComponent que implementa el método Operation de la interfaz Component.
Luego tenemos una clase Decorator, que también implementa la interfaz Component. La clase Decorator tiene una variable miembro de tipo Component.
Tanto las clases ConcreteDecoratorA como ConcreteDecoratorB heredan de la clase Decorator e implementan funcionalidades adicionales sobrescribiendo el método Operation.
4.3. Paso de Implementación 1: Definir la interfaz y la clase de implementación
type Component interface {
Operation() string
}
type ConcreteComponent struct {}
func (c *ConcreteComponent) Operation() string {
return "operación específica del componente"
}
4.4. Paso de Implementación 2: Definir el decorador
type Decorator struct {
component Component
}
func (d *Decorator) Operation() string {
return d.component.Operation()
}
4.5. Paso de Implementación 3: Implementación del decorador
type ConcreteDecoratorA struct {
Decorator
addedState string
}
func (c *ConcreteDecoratorA) Operation() string {
c.addedState = "Nuevo Estado"
return c.addedState + " " + c.component.Operation()
}
type ConcreteDecoratorB struct {
Decorator
}
func (c *ConcreteDecoratorB) Operation() string {
return "operación específica del decorador B " + c.component.Operation()
}
4.6. Paso de Implementación 4: Uso del decorador
func main() {
componente := &ConcreteComponent{}
decoradorA := &ConcreteDecoratorA{}
decoradorA.component = componente
decoradorB := &ConcreteDecoratorB{}
decoradorB.component = decoradorA
resultado := decoradorB.Operation()
fmt.Println(resultado)
}
5. Comparación del Patrón Decorador con Otros Patrones de Diseño
5.1. Comparación con la Herencia
En comparación con la herencia, el patrón decorador puede agregar dinámicamente funcionalidad sin modificar el código existente, mientras que la herencia es estática y debe determinarse en tiempo de compilación.
5.2. Comparación con el Patrón de Proxy Estático
Tanto el patrón decorador como el patrón de proxy estático pueden lograr la extensión de funciones, pero el patrón decorador es más flexible y permite la adición y eliminación dinámica de funcionalidades.
5.3. Comparación con el Patrón de Proxy Dinámico
Tanto el patrón decorador como el patrón de proxy dinámico pueden extender la funcionalidad de los objetos en tiempo de ejecución. Sin embargo, el patrón decorador decora un solo objeto, mientras que el patrón de proxy dinámico involucra un acceso indirecto entre el objeto proxy y el objeto destino.