miércoles, 22 de julio de 2015

9. Patrones (II) - Decorator

El código salvaje crece de una manera incontrolada, esto hace que en muchos casos se pierda el control del mismo, y en casos extremos se tengan que hacer completos proyectos que si bien en su fase de diseño fueron muy buenos, con una arquitectura estable, conforme se van agregando nuevas funcionalidades y más desarrolladores modifican el código, estos se convierten en verdaderos monstros de Frankenstein.

Muchas piezas de código operando para crear nuevas funcionalidades, y en ciertas ocasiones por no conocer el sistema, estas hacen que el sistema sea inestable.

El tiempo de desarrollo se incrementa, la calidad baja, y de la misma forma baja la satisfacción del cliente.

Pero, ¿Hay alguna forma de modificar funcionalidad que sea no tan dolorosa?

Vamos a platicar de un patrón de diseño que es para esto, su nombre es Decorator, y se emplea para añadir de manera dinámica funcionalidad a un objeto, de esta forma podemos incrementar las características del objeto, sin que esto nos represente un cambio doloroso.

Eso si hay que cambiar un poco nuestra mentalidad para usarlo, y pensar más en términos del patrón
Su principal característica, es que nos permite agregar de manera incremental responsabilidades, el patrón lo aplicamos como si fueran capas y las capas nos brindan nuevas características, imaginemos que es una perla que se está creando y cada capa es una aplicación del patrón.

Este es un patrón estructural y lo podemos usar durante el diseño, mantenimiento o extensión de funcionalidad.

Podemos representar el patrón de la siguiente forma


Sin embargo creo que esto lo podemos ilustrar mejor con un poco de código.

Imaginemos esto somos una fábrica de carros, y vamos y vamos a ponerle el radio a uno de nuestros carros, así que crearemos una interfaz en la cual se encontrara el método encender radio

namespace decorator01
{
    public interface ICarro
    {
        void EncenderRadio();
    }
}

El radio lo vamos a implementar en nuestro modelo básico

public class CarroEstandar : ICarro
    {
        public void EncenderRadio()
        {
            Console.WriteLine("Radio FM - Mono");
        }
    }

Como se puede ver el modelo básico cuenta con un Radio FM con sonido mono aural, bueno viene un nuevo modelo, en el cual se requieren mejoras a este radio, así que tomamos el modelo básico y lo mejoramos

  public class CarroMejorado : ICarro
    {
        ICarro CarroBase;

        public CarroMejorado (ICarro I)
        {
            CarroBase = I;
        }
   
        public void EncenderRadio()
        {
            CarroBase.EncenderRadio();
            Console.WriteLine("Radio Satelital");
        }
}

Ahora el radio cuenta con una nueva función, sin perder la primera, si tuviéramos otro modelo, podemos crearlo ahora partiendo de cualquiera de los modelos anteriores.

public class CarroBlindado : ICarro
    {
        ICarro CarroBase;

        public Boolean DobleBlindado { get; set; }

        public CarroBlindado(ICarro I)
        {
            CarroBase = I;
        }

        public void EncenderRadio()
        {
            CarroBase.EncenderRadio();
            if (DobleBlindado == true)
            {
                Console.WriteLine("Audio Alta calidad");
            }
            else
            {
                Console.WriteLine("Audio Especial");
            }
        }
    }

Construyamos ahora nuestros carros:

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Construyendo carro estandar");
            CarroEstandar cr1 = new CarroEstandar();
            cr1.EncenderRadio();

            Console.WriteLine("Construyendo carro Mejorado");
            CarroMejorado cr2 = new CarroMejorado(cr1);
            cr2.EncenderRadio();

            Console.WriteLine("Construyendo carro blindado");
            CarroBlindado cr3 = new CarroBlindado(cr2);
            cr3.DobleBlindado = true;
            cr3.EncenderRadio();

            Console.ReadLine();
        }

Al iniciar la producción vemos lo siguiente



Como podemos observar se puede agregar funcionalidad de manera dinámica de una forma mucho más libre que empleando la herencia


Di no al código salvaje

No hay comentarios.:

Publicar un comentario