Está en la página 1de 263

INVERSIÓN DE CONTROL

E INYECCIÓN
DE DEPENDENCIAS
• Los conceptos de Inversión de Control e Inyección de Dependencias no son nuevos, sino que se remontan
hasta finales de la década de los 80. Sin embargo, estos conceptos han comenzado a popularizarse debido
a la estrecha relación que mantienen con la aparición de Frameworks como Spring en Java o Unity en .NET.
• Inversión de Control
• El concepto de Inversión de Control fue acuñado originalmente por Martin Fowler, diseñador del patrón 
MVVM (Model View View-Model). Fowler definió el concepto de forma informal denominándolo como
el Principio de Hollywood, en el que, tras una audición, se le decía al actor la famosa frase de No nos
llames, nosotros te llamaremos.
• El principio establece una diferenciación entre el concepto de biblioteca y framework, definiendo el
primero como un simple conjunto de clases, métodos y funciones que son invocadas por el flujo del
programa y que posteriormente devuelven el control a éste (control normal) y el segundo como un diseño
más abstracto y elaborado que se encargará, en algún momento, de invocar el código que el programador
se encargue de codificar (inversión de control).
• El ejemplo expuesto por Fowler no puede ser más sencillo: un control normal sería un simple programa
secuencial de consola en el que el programa va solicitando datos al usuario y realizando operaciones
(cálculos, visualización por pantalla) al recibir las respuestas. Un programa que aplica una inversión de
control, sin embargo, se podría representar como una ventana compuesta por cajas de texto, etiquetas y
botones. El Framework, en este caso, expondría un bucle de espera que detectaría la emisión de eventos,
como la pulsación de un botón, momento en el cual se ejecutaría el código de usuario. El Framework
invocará nuestro código en lugar de realizar la operación contraria.
• El Principio de Inversión de Dependencias
• El segundo concepto se lo debemos a otro de los gurús de la ingeniería del Software, 
Robert C. Martin, creador del desarrollo ágil y de los principios básicos de la programación orientada
a objetos, denominados SOLID.
• Dos de estos principios, de hecho, sirvieron como base para otro de ellos: el concepto de Inversión
de Dependencias:
• Principio Abierto/Cerrado: una entidad software debe ser abierta para su extensión, pero cerrada
para su modificación.
• Principio de Sustitución de Liskov: un objeto siempre debe poder ser reemplazado por una instancia
de una clase derivada sin alterar el funcionamiento del programa, es decir, todos los métodos de una
clase padre deben estar presentes en una clase hija, y esta debe poder asumir el papel de su padre.
• Partiendo de estos principios, Martin escribió un artículo en el que desarrollaría el concepto
de Principio de Inversión de Dependencias. En este artículo establece, a grandes rasgos, que uno de
los grandes problemas del software es el acoplamiento, es decir, la dependencia de clases entre sí.
• El concepto de inversión proviene, por lo tanto, por el giro de 180 grados que se produce respecto al
paradigma habitual en el que los módulos superiores tienden a construirse sobre los inferiores (por
ejemplo, una clase de interfaz de usuario invocando un método de una clase de negocio) y en el que
las abstracciones tienden a depender de los detalles (por ejemplo, una implementación de una
interfaz).
• Inyección de Dependencias
• Llegamos así al tercer concepto en discordia, relacionado con los dos conceptos anteriores: la
inyección de dependencias. Este concepto se basa en hacer que una clase A inyecte objetos en una
clase B en lugar de dejar que sea la propia clase B la que se encargue de crear el objeto (éste último
caso se suele realizar mediante un simple new()).
• La forma más común de realizar la inyección de dependencias es a través de lo que se conoce
como Contenedor DI, que se encarga de realizar la inyección en objetos simples (POJOs o POCOs). Es
probable que, después de esta escueta explicación, haya quien se plantee la pregunta: ¿qué tiene que
ver la inyección de dependencias con el rollo que nos has soltado en los dos apartados anteriores?
Principalmente se basa en que la inyección de dependencias se suele realizar a través de algún tipo de
Framework (Spring, Unity, Castle Windsor…), por lo que se realizará mediante una inversión de
control, haciendo que sea el Framework (concretamente el contendor DI) el que invoque nuestro
código.
• El siguiente ejemplo ilustrará el concepto de inyección de dependencias. Imaginemos que tenemos el
siguiente código, que ilustra el funcionamiento “habitual” de una clase que depende de otra:
Como podemos ver, existe una clase “Vehiculo” que contiene un objeto de la clase “Motor”. La clase
public class Motor
{ “Vehiculo” quiere obtener las revoluciones del motor, por lo que invoca el método GetRevoluciones del
    public void Acelerar() objeto Motor y devuelve su resultado. Este caso se corresponde con una dependencia (el módulo
    { superior -vehículo- depende del módulo inferior -motor-).
        // ...
    } Como primer paso para desacoplar el motor del vehículo podríamos hacer que la clase “Vehiculo” deje
 
    public int GetRevoluciones()
de encargarse de instanciar el objeto “Motor”, pasándoselo como parámetro al constructor. De este
    { modo, la clase “Vehiculo” quedaría de la siguiente manera:
        int currentRPM = 0;
  public class Vehiculo
        // ... {
      private Motor m;
        return currentRPM;  
    }     public Vehiculo(Motor motorVehiculo)
}     {
          // El módulo superior ya no instancia directamente el objeto Motor,
public class Vehiculo         // sino que éste es pasado como parámetro en el constructor
{         m = motorVehiculo;
    private Motor m;     }
   
    public Vehiculo()     public int GetRevolucionesMotor()
    {     {
        m = new Motor();         return m.GetRevoluciones();
    }     }
  }
    public int GetRevolucionesMotor()
    { Simple, ¿verdad? El constructor del vehículo se encarga de
        return m.GetRevoluciones();
    }
inyectar la dependencia dentro del objeto, evitando que esta
} responsabilidad recaiga sobre la propia clase. De este modo,
estamos desacoplando ambos objetos. Si hacemos uso de
interfaces, el acoplamiento será incluso menor.
public class MotorDiesel : IMotor
{
public interface IMotor     public void Acelerar()
{     {
    // Métodos comunes a todos los motores         RealizarAdmision();
    void Acelerar();         RealizarCompresion();
    int GetRevoluciones();         RealizarCombustion();   // Propia del motor diesel
}         RealizarEscape();
      }
public class MotorGasolina : IMotor  
{     public int GetRevoluciones()
    public void Acelerar()     {
    {         int currentRPM = 0;
        RealizarAdmision();  
        RealizarCompresion();         return currentRPM;
        RealizarExplosion();    // Propia del motor de gasolina     }
 
        RealizarEscape();
    }     private void RealizarAdmision() { /* ... */ }
      private void RealizarCompresion() { /* ... */ }
    public int GetRevoluciones()     private void RealizarCombustion() { /* ... */ }
    {     private void RealizarEscape() { /* ... */ }
        int currentRPM = 0; }
   
        // ... public class Vehiculo
  {
        return currentRPM;     private IMotor m;
    }  
      public Vehiculo(IMotor motorVehiculo)
    private void RealizarAdmision()   { /* ... */ }     {
    private void RealizarCompresion() { /* ... */ }         // El módulo superior ya no instancia directamente el objeto
    private void RealizarExplosion()  { /* ... */ } Motor,
    private void RealizarEscape()     { /* ... */ }         // sino que éste es pasado como parámetro en el constructor
          m = motorVehiculo;
}     }
 
    public int GetRevolucionesMotor()
    {
        return m.GetRevoluciones();
    }
}
• Como vemos, el objeto public class Vehiculo
{
Vehiculo ya ni siquiera está     private IMotor m;
 
acoplado a un objeto de la     // Se añade una propiedad para poder acceder al motor
    public IMotor M
clase Motor, sino que bastará     {
un objeto que implemente la         get { return m; }
        set { m = value; }
interfaz IMotor,     }
 
como MotorGasolina y MotorDi     public Vehiculo(IMotor motorVehiculo)
    {
esel. A continuación podremos         // El módulo superior ya no instancia directamente el objeto Motor,
modificar el vehículo         // sino que éste es pasado como parámetro en el constructor
        m = motorVehiculo;
añadiéndole una propiedad     }
 
para poder acceder     public int GetRevolucionesMotor()
directamente al motor e     {
        // Se comprueba que el motor existe antes de invocar uno de sus métodos
invocar sus métodos.         if (m != null)
            return m.GetRevoluciones();
        else
            return -1;
    }
}
• Por último, realizaremos la instanciación public enum TipoMotor
del objeto a través de una clase que {
    MOTOR_GASOLINA = 0,
implemente el patrón Factoría.     MOTOR_DIESEL = 1
Definiremos una enumeración que }
public class VehiculoFactory
establecerá el tipo de motor que {
deseamos que tenga nuestro vehículo.     public static Vehiculo Create(TipoMotor tipo)
    {
        Vehiculo v = null;
Por lo tanto, hemos conseguido inyectar la  
dependencia motor dentro del objeto vehículo         switch(tipo)
        {
haciendo que el vehículo no dependa del motor, sino             case TipoMotor.MOTOR_DIESEL:
que sea la factoría (clase externa a ambos elementos)                 v = new Vehiculo(new MotorDiesel());
la que se encargue de este trabajo. Para el                 break;
            case TipoMotor.MOTOR_GASOLINA:
programador, la instanciación del objeto no tendrá                 v = new Vehiculo(new MotorGasolina());
mucha más complicación, ya que pasará de instanciar                 break;
el objeto de esta forma:             default:
                break;
        }
         
        return v;
    }
}
• Nótese que la diferencia es estructural: el resultado será el mismo (un
vehículo con un motor), pero si el día de mañana fuese necesario
extender la aplicación (por ejemplo, si el cliente necesita un vehículo
que funcione con un motor de hidrógeno), será suficiente con crear
una nueva clase que implemente la interfaz IMotor y añadir el
proceso de instanciación en la factoría. De este modo, no sería
necesario modificar nada de lo codificado anteriormente. En caso de
haberlo codificado por la vía “habitual”, sería necesario realizar
cambios en la clase vehículo para implementar esta nueva
funcionalidad.
INTRODUCCIÓN A LA
INYECCIÓN DE DEPENDENCIAS
MEDIANTE UNITY
• Tras una pequeña introducción a la inversión de control y a la
inyección de dependencias, veremos cómo se comportan los
contenedores DI en una aplicación práctica. Para ello hablaremos de
Unity, desarrollado por Microsoft y perteneciente al paquete 
Enterprise Library.
• Unity es, por tanto, un Framework de inyección de dependencias o DI
Container. Puede ser descargado desde Codeplex o utilizando NuGet
dentro de Visual Studio, método este último que utilizaremos en
nuestro ejemplo.
• Comenzaremos creando un nuevo proyecto de consola al que
llamaremos, por ejemplo, UnityExample.
A continuación haremos uso de NuGet para añadir
nuestra referencia a Unity. Será tan sencillo como
hacer click derecho sobre las referencias del
proyecto y seleccionar la opción Manage NuGet
Packages…
• Seleccionaremos la opción Online en el árbol de la derecha y
escribiremos Unity en la caja de búsqueda para obtener el paquete.
Una vez encontrado, pulsaremos sobre el botón Install.
• Creando las clases para el ejemplo
• Realizaremos un ejemplo similar al del artículo anterior, salvo que en
lugar de utilizar motores y coches, imaginaremos una ludoteca con
mesas, en cada una de las cuales puede jugarse a un juego de mesa. La
clase Table será la engargada de modelar la mesa, mientras que la
interfaz IGame simbolizará las operaciones comunes a todos los juegos:
añadir jugadores, eliminarlos y mostrar el estado actual del juego.
• Crearemos un par de juegos que implementarán la
interfaz: TrivialPursuit y TicTacToe (el típico tres en raya).
• Comenzaremos codificando la interfaz. {
public interface IGame

    string Name { get; }


    int CurrentPlayers { get; }
    int MinPlayers { get; }
    int MaxPlayers { get; }
 
    void addPlayer();
    void removePlayer();
    void play();
    string result();
}
 public void addPlayer()
public class TrivialPursuit : IGame     {
{         CurrentPlayers++;
    private string _status;     }
   
    public TrivialPursuit()     public void removePlayer()
    {     {
        Name = "Trivial Pursuit";         CurrentPlayers--;
        CurrentPlayers = 0;     }
        MinPlayers = 2;  
        MaxPlayers = 8;     public void play()
    {
        _status = "Sin juego activo";
        if ((CurrentPlayers > MaxPlayers) || (CurrentPlayers < MinPlayers))
    }             _status = string.Format("{0}: No es posible jugar con {1} jugadores.", Name,
  CurrentPlayers);
    #region IGame Members         else
              _status = string.Format("{0}: Jugando con {1} jugadores.", Name, CurrentPlayers);
    public string Name { get; set; }     }
       
    public int CurrentPlayers { get; set; }     public string result()
      {
    public int MinPlayers { get; set; }         return _status;
      }
    public int MaxPlayers { get; set;  }  
    #endregion
}
public class TicTacToe : IGame public void addPlayer()
{     {
    private string _status;         CurrentPlayers++;
      }
    public TicTacToe()  
    {     public void removePlayer()
        Name = "Tres en Raya";     {
        CurrentPlayers = 0;         CurrentPlayers--;
        MinPlayers = 2;     }
        MaxPlayers = 2;  
        _status = "Sin juego activo";     public void play()
    }     {
          if ((CurrentPlayers > MaxPlayers) || (CurrentPlayers < MinPlayers))
    #region IGame Members             _status = string.Format("{0}: No es posible jugar con {1} jugadores.", Name,
  CurrentPlayers);
    public string Name { get; set; }         else
              _status = string.Format("{0}: Jugando con {1} jugadores.", Name, CurrentPlayers);
    public int CurrentPlayers { get; set; }     }
   
    public int MinPlayers { get; set; }     public string result()
      {
    public int MaxPlayers { get; set; }         return _status;
    }
 
    #endregion
}
public class Table

Finalmente,
{
    private IGame game;
 
    public Table(IGame game)
    {
        this.game = game;
    }
codificaremos la
clase Table que contendrá
 
    public string GameStatus()
    {

una interfaz IGame que
        return game.result();
    }
 
    public void AddPlayer()
    {
        game.addPlayer();
    }
será inyectada a través de
su constructor.
 
    public void RemovePlayer()
    {
        game.removePlayer();
    }
 
    public void Play()
    {
        game.play();
    }
}
• Registro de tipos Lo primero que deberemos hacer será instanciar un
contenedor de Unity y registrar los tipos que queramos que resuelva
por nosotros. Como primer ejemplo, registraremos la
interfaz IGame con la clase TrivialPursuit. Esto significará que, cuando
resolvamos las dependencias, Unity instanciará un objeto de la
clase TrivialPursuit en el momento en el que resolvamos un objeto
que posea una dependencia de tipo IGame.
static void Main(string[] args)
{
    // Declaramos un contenedor Unity
    var unityContainer = new UnityContainer();
 
    // Registramos IGame para que cuando se detecte la dependencia
    // proporcione una instancia de TrivialPursuit
    unityContainer.RegisterType<IGame, TrivialPursuit>();
}
• Resolución de tipos Por tanto, cada vez que le pidamos a Unity que
resuelva una interfaz IGame, el Framework buscará si tiene registrado
el tipo y, en caso afirmativo, proporcionará una instancia de la clase
que se haya mapeado (en este caso, TrivialPursuit:

// Hacemos que Unity resuelva la interfaz, proporcionando una instancia


// de la clase TrivialPursuit
var game = unityContainer.Resolve<IGame>();
 
// Comprobamos que el funcionamiento es correcto
game.addPlayer();
game.addPlayer();
Console.WriteLine(string.Format("{0} personas están jugando a {1}", game.CurrentPlayers,
game.Name));
Console.ReadLine();

Si le indicamos a Unity que resuelva una instancia de la clase Table, lo que lograremos será que se inyecten
todas aquellas dependencias que Unity tiene registradas, es decir, nos proporcionará una instancia de la
clase Table inyectando un objeto de la clase TrivialPursuit en el momento en el que se encuentre con una
interfaz IGame:

// Instanciamos un objeto de la clase Table a través de Unity


var table = unityContainer.Resolve<Table>();
• El constructor de Table recibe como parámetro una referencia a la
interfaz IGame. Por tanto, Unitybuscará en su lista de registros y
concluirá que debe inyectar una nueva instancia (new TrivialPursuit())
en el lugar de la interfaz. Añadiremos el código siguiente para
comprobar si todo ha funcionado correctamente:
static void Main(string[] args)
{
    // Declaramos un contenedor Unity
    var unityContainer = new UnityContainer();
 
    // Registramos IGame para que cuando se detecte la dependencia
    // proporcione una instancia de TrivialPursuit
    unityContainer.RegisterType<IGame, TrivialPursuit>();
     
    // Instanciamos un objeto de la clase Table a través de Unity
    var table = unityContainer.Resolve<Table>();
 
    table.AddPlayer();
    table.AddPlayer();
    table.Play();
 
    Console.WriteLine(table.GameStatus());
 
    Console.ReadLine();
}
• Inyección de propiedades Además de lo visto hasta el
momento, Unity nos permite realizar otras operaciones, tales como
asignar valores a propiedades a la hora de realizar la resolución de
tipos.
// Inyectamos una propiedad cuando se resuelva la dependencia
InjectionProperty injectionProperty = new InjectionProperty("Name", "Trivial Pursuit Genus Edition");
unityContainer.RegisterType<IGame, TrivialPursuit>(injectionProperty);

• Esto hará que, a la hora de resolver IGame se obtenga una instancia


de TrivialPursuit cuya propiedad Name tendrá el valor Trivial Pursuit
Genus Edition. Si usamos estas líneas de código para sustituir a las
anteriores, veremos que el resultado es correcto:
• Inyección de parámetros Otra de las posibilidades de las que
disponemos a la hora de inyectar una dependencia es realizar la
inyección en el momento en el que resolvemos la dependencia. Hasta
ahora hemos visto el caso en el que el juego que se instancia por
defecto es TrivialPursuit. Sin embargo, puede haber casos en los que
nos interese que IGame se corresponda con otro juego. Podemos
indicar a Unity que nos proporcione una instancia de, por
ejemplo, TicTacToe, inyectándole los parámetros del constructor a la
hora de resolver la dependencia.
• Es decir: la clase Table posee un constructor con un parámetro de
tipo IGame llamado game.
public Table(IGame game)
{
    this.game = game;
}
• Si no lo indicamos de forma explícita, Unity resolverá el
parámetro game de forma automática realizando una búsqueda en
las dependencias que tiene registradas (en este caso se
correspondería con TrivialPursuit). Sin embargo, es posible decirle al
contenedor que resuelva la dependencia de la forma que nosotros le
indiquemos. Por ejemplo:
// Sobrecargamos el parámetro del constructor de Table
var table2 = unityContainer.Resolve<Table>(new ParameterOverride("game", new TicTacToe()));
 
table2.AddPlayer();
table2.AddPlayer();
table2.Play();
 
Console.WriteLine(table2.GameStatus());
Console.ReadLine();
• La inyección de dependencias, dentro del paradigma de la programación orientada a objetos, es uno de
los cinco principios SOLID, y como tal, debe utilizarse siempre que sea posible.
• Acerca de qué tecnología utilizar, dependerá de cada uno. No es necesario utilizar Unity para abrazar
este principio, ya que para inyectar dependencias basta con codificar las referencias a objetos externos
a la clase como abstracciones (por ejemplo, interfaces) y que sean instanciados fuera de la clase,
recibiéndose como parámetros de métodos o constructores.
• En cuanto al ejemplo concreto, entiendo perfectamente tu duda. De hecho, Unity está desaconsejado
en diseños sencillos en los que la inyección de dependencias pueda realizarse de forma “manual”, tal y
como has ejemplificado.
• La ventaja de utilizar Unity es, principalmente, la resolución dinámica de dependencias cuando éstas se
encuentran “encadenadas” (existe una jerarquía de dependencias que hay que resolver). Si observas el
ejemplo, al resolver la clase “Table”, Unity es capaz de resolver también en tiempo de ejecución
aquellas dependencias de esta clase que estén registradas en el contenedor. Por lo tanto, si
realizáramos un simple “IGame game = new TrivialPursuit()”, si quisiéramos instanciar un objeto de la
clase Table, en primer lugar deberíamos instanciar “game” y posteriormente inyectarle la instancia a
“table”. Unity realiza este proceso por nosotros, resolviendo todas las dependencias que “cuelgan” de
una clase de forma automática.
• Por lo tanto, en un ejemplo tan sencillo, utilizar Unity no tendría mucho sentido (salvo que exista una
previsión en el aumento de dependencias de nuestro modelo de clases).
• Puedes encontrar un par de ejemplos más elaborados desde aquí: 
https://unity.codeplex.com/downloads/get/683531
PATRONES DE DISEÑO
• Un patrón de diseño no es más que una “receta” que trata de proporcionar una
solución genérica a un problema concreto que se repite con frecuencia durante
el desarrollo de software.
• Para que un patrón de diseño sea considerado como tal debe cumplir una serie
de requisitos, como el haber demostrado su efectividad a la hora de resolver el
problema que afirma solventar y ser adaptable a cualquier entorno y
tecnología, es decir, ser lo suficientemente genérico para asegurar su
reutilización.
• Por tanto, un patrón de diseño es un artefacto, por definición, abstracto. Sé que
existe multitud de documentación al respecto, pero muchas de las
explicaciones que se ofrecen se componen de un montón de terminología que,
si bien es perfectamente familiar para un ingeniero experimentado, resulta
terriblemente difícil de digerir para un recién iniciado en el mundo de la
arquitectura y el diseño. Dicen que Einstein dijo en una ocasión que “no
entiendes realmente algo a menos que seas capaz de explicárselo a tu abuela”. 
• Antipatrones de diseño
• Puede que ahora mismo estés pensando: ¡eh! ¡yo soy un buen
ingeniero y no uso esos patrones de diseño! ¡diseño los míos! Bien, al
igual que existen patrones de diseño, existe también su antítesis, los “
antipatrones de diseño“, es decir, aquello que nunca, bajo ninguna
circunstancia, hay que realizar a la hora de diseñar un software. Y
(casualidades de la vida), uno de esos antipatrones recibe el nombre
de “Reinventar la rueda“: no pierdas el tiempo en investigar algo que
ya ha sido descubierto. Puedes intentar mejorar o adaptar una
solución existente, especialmente si un elemento no se adapta bien a
tu proyecto, pero comenzar el trabajo desde cero es perder el tiempo:
hay gente que ha invertido muchísimo tiempo en estos patrones.
Funcionan. No le des más vueltas.
• Categorías de patrones de diseño
• El Gang of Four estableció una serie de categorías para definir la función que
realizaba un patrón de diseño. A grandes rasgos, los patrones se dividen en tres
grupos:
• Creacionales: se trata de un conjunto de patrones cuyo objetivo es el de instanciar
objeto, en lugar de recurrir a la instanciación directa.
• Estructurales: definen una composición de objetos que, a través de especialización,
proporcionan una funcionalidad determinada.
• De comportamiento: se centran en cómo interactúan e intercambian información
unos objetos con otros de una manera definida.
• Con el paso del tiempo han surgido nuevos patrones de diseño, algunos de los
cuales no son más que una combinación o versión de los patrones “de toda la vida”.
Realizaré, por tanto, una introducción a los patrones más importantes utilizando la
clasificación original del GoF. Comenzaremos por los patrones creacionales, en los
que nos serán útiles los conceptos de inyección de dependencias.
PATRONES DE
CREACION
FACTORY PATTERNS
(INTRODUCCIÓN)

• Habíamos quedado en que los patrones creacionales o de creación eran


aquellos en los que se delegaba la instanciación de un objeto en otro en
lugar de recurrir a un simple new(). La pregunta que nos hacemos es: ¿por
qué hacer esto? ¿Qué interés práctico puede existir en crear una clase cuya
función sea instanciar otras clases pudiendo dejarle el trabajo a la clase
original?
• Bien, esta forma de trabajar puede ser útil en algunos escenarios, pero el
principal suele involucrar el no saber qué objeto vamos a instanciar hasta el
momento de la ejecución. Valiéndonos del polimorfismo podremos utilizar
una interfaz para alojar una referencia a un objeto que será instanciado por
un tercero en lugar de dejar que sea el propio constructor del objeto el que
proporcione la instancia.
Por tanto, nuestro objetivo principal será la encapsulación de la
Hablando en plata, pasaremos de esto:
creación de objetos. Volveremos al ejemplo que hemos usado
MotorDiesel motor = new MotorDiesel(); en otras ocasiones: vehículos con un motor que está
representado mediante una interfaz que será implementada por
a esto otro: las clases MotorDiesel y MotorGasolina. La interfaz expondrá
las siguientes propiedades y métodos:
IMotor iMotor = MotorFactory.CreateInstance(tipoMotor);

namespace Patterns.Factory.SimpleFactory.Interfaces
{
    public interface IMotor
    {
        public int Estabilidad { get; set; }
        public decimal ParMotor { get; set; }
        public int Potencia { get; set; }
        public decimal Rendimiento { get; set; }
        public int VelocidadNominal { get; set; }
 
        string ConsumirCombustible();
        string InyectarCombustible();
        string RealizarEscape();
        string RealizarExpansion();
    }
}
public class MotorDiesel : IMotor
{
    #region IMotor Members
 
    int Estabilidad { get; set; }
    decimal ParMotor { get; set; }
    int Potencia { get; set; }
    decimal Rendimiento { get; set; }
    int VelocidadNominal { get; set; }
 
    public string ConsumirCombustible()
    {
        return RealizarCombustion();
    }
 
    public string InyectarCombustible(int cantidad)
    {
        return string.Format("MotorDiesel: Inyectados {0} ml. de Gasoil.", cantidad);
    }
 
    public string RealizarEscape()
    {
        return "MotorDiesel: Realizado escape de gases";
    }
 
    public string RealizarExpansion()
    {
        return "MotorDiesel: Realizada expansion";
    }
 
    #endregion
 
    private string RealizarCombustion()
    {
        return "MotorDiesel: Realizada combustion del Gasoil";
    }
}
public class MotorGasolina : IMotor
{
    #region IMotor Members
 
    public int Estabilidad { get; set; }
    public decimal ParMotor { get; set; }
    public int Potencia { get; set; }
    public decimal Rendimiento { get; set; }
    public int VelocidadNominal { get; set; }
 
    public string ConsumirCombustible()
    {
        return RealizarExplosion();
    }
 
    public string InyectarCombustible(int cantidad)
    {
        return string.Format("MotorGasolina: Inyectados {0} ml. de Gasolina.", cantidad);
    }
 
    public string RealizarEscape()
    {
        return "MotorGasolina: Realizado escape de gases";
    }
 
    public string RealizarExpansion()
    {
        return "MotorGasolina: Realizada expansion";
    }
 
    #endregion
 
    private string RealizarExplosion()
    {
        return "MotorGasolina: Realizada explosion de la Gasolina";
    }
}
• Finalmente, crearemos una clase MotorFactory que exhiba un
método público CreateInstance(nombreClase) para instanciar, por
ejemplo, un motor Diesel.
public class MotorFactory
{
    public IMotor CreateInstance(string tipoMotor)
    {
        IMotor resultado;
 
        switch (tipoMotor)
        {
            case "MotorDiesel":
                resultado = new MotorDiesel() { Estabilidad = 100, Potencia = 40, Rendimiento = 800, VelocidadNominal = 0 };
                break;
            default:
                resultado = null;
                break;
        }
 
        return resultado;
    }
}
• Lo que estamos haciendo aquí no es otra cosa que delegar
en MotorFactory la tarea de instanciar el motor. Ya tenemos el motor
Diesel. Nos falta ahora el Gasolina. Para ello deberemos modificar la
clase MotorFactory y añadir un nuevo case a la sentencia switch:
public class MotorFactory
{
    public IMotor CreateInstance(string tipoMotor)
    {
        IMotor resultado;
 
        switch (tipoMotor)
        {
            case "MotorDiesel":
                resultado = new MotorDiesel();
                break;
            case "MotorGasolina":
                resultado = new MotorGasolina();
                break;
            default:
                resultado = null;
                break;
        }
 
        return resultado;
    }
}
• Si quisiéramos obtener un motor diesel, por lo tanto, bastaría con el siguiente
código:
static void Main(string[] args)
{
    MotorFactory factory = new MotorFactory();
 
    IMotor motorDiesel = factory.CreateInstance("MotorDiesel");
 
    if (motorDiesel == null)
        return;
 
    Console.WriteLine(motorDiesel.InyectarCombustible(20));
    Console.WriteLine(motorDiesel.ConsumirCombustible());
    Console.WriteLine(motorDiesel.RealizarExpansion());
    Console.WriteLine(motorDiesel.RealizarEscape());
    Console.ReadLine();
}
• Principios SOLID Lo que acabamos de hacer es delegar la decisión de instanciar
un motor u otro hasta el momento en el que la variable tipoMotor llega a
nuestro método CreateInstance, lo cual flexibiliza el código permitiendo que no
nos atemos a un tipo de motor concreto en tiempo de compilación. Sin
embargo, al aparecer un nuevo tipo de motor hemos tenido que modificar una
clase para incluir el nuevo elemento a instanciar.
• Si recordamos el artículo sobre la inyección de dependencias, comentamos por
encima los Principios SOLID propuestos por Robert C. Martin, que eran los
siguientes:
• Responsabilidad única: un objeto sólo debe tener una única responsabilidad.
• Abierto/cerrado: una clase debe estar abierta para su extensión, pero cerrada para su
modificación.
• Principio de sustitución de Liskov: una clase padre siempre debe poder ser sustituida por
una clase hija sin alterar el comportamiento del programa.
• Segregación de la Interfaz: es preferible contar con muchas interfaces específicas que
con una de propósito general.
• Inversión de dependencia: se debe depender de abstracciones, no de concreciones.
• Si cada vez que aparezca un nuevo motor tenemos que modificar nuestra
factoría para darle cabida en nuestro proceso de instanciado, estaremos
violando directamente el principio abierto/cerrado, ya que las clases
deben extenderse, no modificarse.
• Por lo tanto, lo que estamos afirmando es que es necesario encontrar un
modo de generalizar nuestra factoría de tal modo que no sea necesario
modificarla en el caso de que un nuevo tipo se añada al ensamblado. El
problema, a simple vista, parece irresoluble por métodos ajenos a la
brujería. Sin embargo, recordemos que la razón de ser de los patrones de
diseño era precisamente esta: proporcionar soluciones generales a
problemas concretos. Y este problema concreto tiene una solución más
sencilla de lo que parece: bucear en las tripas del ensamblado y generar
un listado de pares clave-valor con los tipos que se ajusten a lo que
necesitamos. Entraremos, por lo tanto, en el campo de Reflection.
• Configurando la factoría mediante un fichero XML Un primer acercamiento
puede ser el siguiente: crear una sección en nuestro fichero de configuración (o
cualquier otro fichero XML, base de datos…) que contenga el nombre de las
clases que nuestra factoría puede generar. El constructor de la factoría iterará
sobre estos elementos y creará un diccionario con pares clave-valor cuya clave
será el nombre del tipo indicado en el fichero y cuyo valor correspondiente será
el tipo en sí. Por tanto, añadiremos una nueva sección a nuestro fichero
app.config, del siguiente modo:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="AllowedMotorTypes" type="System.Configuration.NameValueSectionHandler" />
    </configSections>
   
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
   
    <AllowedMotorTypes>
      <add key="Patterns.Factory.SimpleFactory.Motores.MotorDiesel" value="true" />
      <add key="Patterns.Factory.SimpleFactory.Motores.MotorGasolina" value="true" />
    </AllowedMotorTypes>
 
</configuration>
• A continuación añadiremos una referencia a la biblioteca System.Configuration, y
haremos uso del siguiente código para lograr nuestro objetivo: instanciaremos un
objeto de la clase NameValueCollection que simbolizará la sección que hemos
creado, y usaremos una sentencia LINQ para iterar sobre todas las claves de la
sección. Sobre esta consulta usaremos el método de
extensión ToDictionary(campoClave, campoValor) en los que indicaremos el
contenido de keypara la clave y, a través de Reflection, recuperaremos el tipo
correspondiente a esa clave para almacenarlo como valor.
private void ConfiguracionDesdeXml()
{
    // Extraemos los pares clave-valor del fichero de configuracion, concretamente de
    // la seccion AllowedMotorTypes
    NameValueCollection settings = ConfigurationManager.GetSection("AllowedMotorTypes") as NameValueCollection;
 
    if (settings != null)
    {
        // Instanciamos el diccionario<nombreTipo, tipo>
        tiposInstanciables = (from clave in settings.AllKeys            // Recorremos todas las claves
                              where bool.Parse(settings[clave])         // ...en las que value sea "true"
                              select clave).ToDictionary(key => key,    // La clave del diccionario sera "key"
                                     key => Assembly.GetExecutingAssembly().GetType(key)); // El valor sera el tipo
    }
 
}
• Configurando la factoría mediante las clases del ensamblado
• Una segunda posibilidad consiste en recorrer todas las clases existentes en el
ensamblado, comprobar si implementan la interfaz IMotor y, en caso
afirmativo, añadirla a un diccionario en el que se relacione el nombre de la
clase con el tipo que representa. Una vez que se invoque el
método CreateInstance, se consultará el diccionario usando el parámetro del
método como clave y se instanciará el tipo asociado mediante la
clase Activator.
• Resumiendo, el proceso será el siguiente:
• Al instanciar la factoría, se recorren todas las clases del ensamblado.
• Por cada clase del ensamblado
• Si la clase implementa la interfaz que nuestra factoría se encarga de instanciar, se añade al
diccionario(nombreClase, tipo)
• Al invocar el método CreateInstance(nombreClase), se consulta el diccionario
y se recupera el tipo asociado, instanciándolo mediante Activator.
private void ConfiguracionAutomatica()
{
    // Usamos LINQ para obtener un diccionario (nombreClase, tipoClase) a partir de todos
    // aquellos tipos del ensamblado actual que implementen la interfaz IMotor.
    tiposInstanciables = (from tipo in Assembly.GetExecutingAssembly().GetTypes()
                          where tipo.GetInterface(typeof(IMotor).ToString()) != null
                          select tipo).ToDictionary(t => t.ToString(),  // Clave: nombre del tipo
                                                    t => t);            // Valor: tipo
 
}

Como vemos, el proceso de recorrer el ensamblado no es más que una forma de configurar la factoría. Este proceso no
tiene por qué ser como el que aquí se expone: puede recorrerse un fichero XML, una base de datos o cualquier otra forma
de proporcionar a nuestra factoría un método de saber qué clases puede instanciar.
El siguiente paso será obtener el tipo a partir de la cadena de texto que recibirá nuestro método CreateInstance(). Esto será
tan sencillo como consultar el diccionario y devolver el resultado.

private Type ObtenerTipo(string nombreTipo)


{
    if (tiposInstanciables == null)
        return null;
    else
        return (tiposInstanciables.ContainsKey(nombreTipo) ? tiposInstanciables[nombreTipo] : null);
}
• Por último, codificaremos el método CreateInstance(), que obtendrá
el tipo del diccionario a partir de la cadena de texto e instanciará el
objeto a partir de su tipo. Existen varias formas de realizar esta
operación. La primera de ellas será mediante el
método Activator.CreateInstance(tipo). Esta invocación equivale al
constructor por defecto de la clase:
public IMotor CreateInstance(string tipoMotor)
{
    // Usamos Activator.CreateInstance(tipo) para instanciar el objeto de forma dinamica
    IMotor resultado = (IMotor)Activator.CreateInstance(ObtenerTipo(tipoMotor));
 
    return resultado;
}
• Un segundo método sería a través del
método tipo.GetConstructor(arrayConTiposDeLosParámetros).Invoke(arrayConLosParámetros). En el
supuesto de que el constructor no posea parámetros (constructor por defecto), le pasaríamos el
valor Type.EmptyTypes a GetConstructor y null al método Invoke.
// Otra forma de instanciar el objeto podria haber sido obteniendo el constructor por
// defecto e invocarlo mediante el metodo Invoke
IMotor resultado = (IMotor)ObtenerTipo(tipoMotor).GetConstructor(Type.EmptyTypes).Invoke(null);

En caso de que el constructor que queremos invocar requiriese por ejemplo un valor entero, le pasaríamos un
array con un único elemento con el tipo entero a GetConstructor y un array con un único elemento entero al
método Invoke.
// Si tuviesemos un constructor del estilo a MotorFactory(int dato), esta ultima invocacion
// equivaldria a  "new MotorFactory(34)":
IMotor resultado = (IMotor)ObtenerTipo(tipoMotor).GetConstructor(new[] {typeof(int) }).Invoke(new object[] {34} );
Patrón Factory Method
• Hasta ahora hemos explicado el concepto de factoría: una clase especializada en crear objetos. A partir de
aquí, podemos especializar aún más estas factorías para que generen tipos concretos. El patrón Factory
Method es similar a lo que hemos visto hasta ahora, con una pequeña variación: el
método CreateInstance() ya no generará una instancia, sino que o bien se convertirá en abstracto o bien
pertenecerá a una interfaz y dejará a las clases que la implementen la tarea de codificar su comportamiento.
Por lo tanto, nuestra clase MotorFactory ya no podrá utilizarse directamente para generar objetos, sino que
habrá que crear una nueva clase que herede de MotorFactory que implemente el método CreateInstance() o
bien transformar MotorFactory en una interfaz IMotorFactory y dejar a las clases que la implementen el
trabajo de instanciar las clases.
• ¿Qué conseguimos con esto? Básicamente, especializar las factorías. En lugar de tener una única factoría que
centralice todo el proceso de creación de objetos, tendremos varias clases factoría que heredan
de MotorFactory (o implementan IMotorFactory) que estarán especializadas en crear variantes concretas.
• En nuestro ejemplo sólo exponemos el caso de la instanciación de dos clases: MotorDiesel y MotorGasolina.
Además, las diferencias entre ambas clases son mínimas, por lo que una factoría simple nos bastaría para
nuestro diseño. Pero, ¿qué ocurriría si estas clases se especializaran cada vez más y más? ¿Y si se añadiesen
muchos más tipos de motores? Quizás la carga funcional sobre nuestra factoría sería demasiada, por lo que
sería aconsejable pasar al siguiente paso: utilizar Factory Method para especializar las factorías.
• Vamos a realizar, por lo tanto, el siguiente proceso:
• 1) Eliminar la clase MotorFactory y sustituirla por la
interfaz IMotorFactory. Esta nueva interfaz expondrá el
método CreateInstance(), que deberá ser implementado por otras
clases.
• 2) Crear dos nuevas
clases, MotorDieselFactory y MotorGasolinaFactory, que
implementen la interfaz IMotorFactory y su método CreateInstance(),
especializando el proceso de instanciado. El nombre del
patrón Factory Method viene precisamente de aquí.
• Fijémonos en que el método CreateInstance sigue devolviendo una
interfaz IMotor. Podríamos pensar en que sería mejor
que MotorGasolinaFactory.CreateInstance() devolviera una instancia
de MotorGasolina, ¿verdad? Bien, en realidad lo hará, pero
recordemos que MotorGasolina implementa la interfaz IMotor, por lo
que puede usar esta referencia para devolver una instancia
de MotorGasolina tal y como lo ha venido haciendo hasta ahora.
Dejemos el nivel de abstracción lo más alto posible: la concreción no
es buen amigo del diseñador.
• Por tanto, el código de la interfaz IMotorFactory se simplificará hasta
el punto de exponer únicamente la firma del
método CreateInstance(): public interface IMotorFactory
{
    IMotor CreateInstance();
}
• Configurando la factoría por defecto
• Anteriormente vimos cómo podíamos configurar qué clases estaban
disponibles para su instanciado: mediante el recorrido de todas las
clases del ensamblado que implementaban la interfaz IMotor o
mediante su inclusión en el fichero de configuración .config.
• Sin embargo, en lugar de usar un fichero .config para estas tareas, es
más aconsejable usar para ello un fichero .settings. Este fichero
consiste en una especie de diccionario al que se puede acceder
mediante la clase Settings (o Properties.Settings, dependiendo del
Framework). Para añadir un fichero de este tipo, agregaremos un
nuevo elemento a nuestro proyecto de tipo Settings File.
A continuación, añadiremos un nuevo par clave-valor. El valor consistirá en el nombre
de la clase de la factoría que queremos utilizar. Por supuesto, podríamos utilizar varios
pares clave-valor (en la práctica es lo que se hace) dependiendo del contexto. Esto nos
puede servir, entre otras cosas, para instanciar distintos elementos dependiendo de si
estamos desarrollando en producción, pruebas unitarias, en desarrollo…
Hecho esto, creamos un método ObtenerFactoria() que devuelva una interfaz IMotorFactory que alojará
la instancia de la factoría concreta que queremos utilizar y que vendrá determinada por el contenido del
valor que hemos guardado en la configuración.

private static IMotorFactory ObtenerFactoria()


{
    // Obtenemos el nombre de la clase de la configuracion (Settings)
    string nombreFactoria = Settings.Default.MotorFactory;
 
    // Mediante Reflection, obtenemos el ensamblado e instanciamos la factoria a
    // partir del nombre de la clase (esto llamará a su constructor por defecto)
    Assembly ensamblado = Assembly.GetExecutingAssembly();
    IMotorFactory factoria = (IMotorFactory)ensamblado.CreateInstance(nombreFactoria);
 
    // Devolvemos la instancia de la factoría
    return factoria;
}
• Codificando las factorías concretasLo siguiente será configurar el código de
nuestras factorías individuales: MotorDieselFactory y MotorGasolinaFactory. En
estas clases se codificará el comportamiento del método CreateInstance(),
realizando las operaciones que consideremos oportunas para cada tipo de motor,
como asignarle valores a sus propiedades o realizar tareas fijas de inicialización.
Por ejemplo:
public class MotorGasolinaFactory : IMotorFactory public class MotorDieselFactory : IMotorFactory
{ {
    #region IMotorFactory Members     #region IMotorFactory Members
   
    public IMotor CreateInstance()     public IMotor CreateInstance()
    {     {
        IMotor motorGasolina = new MotorGasolina()         IMotor motorDiesel = new MotorDiesel()
        {         {
            Estabilidad = 100,             Estabilidad = 60,
            ParMotor = 40,             ParMotor = 90,
            Potencia = 1200,             Potencia = 700,
            Rendimiento = 420,             Rendimiento = 220,
            VelocidadNominal = 47             VelocidadNominal = 80
        };         };
   
        return motorGasolina;         return motorDiesel;
    }     }
   
    #endregion     #endregion
} }
• El diagrama de clases asociado a nuestro modelo tendría, por tanto, el
siguiente aspecto:
• Utilizando Factory Method
• Finalmente, haremos uso de Factory Method mediante los siguientes
pasos:
• Usamos una interfaz de la factoría (genérica) para alojar una instancia
de la factoría concreta, que será generada mediante el
método ObtenerFactoria() accediendo a la configuración para decidir
qué factoría debe instanciar.
• Usamos una interfaz del motor (genérica) para alojar una instancia de
un motor concreto, que será generado mediante el
método CreateInstance() de la factoría generada previamente.
• Hacemos uso de los métodos del objeto a través de su interfaz.
static void Main(string[] args)
{
    // Usamos un método genérico para instanciar la factoría por defecto.
    // La factoría estará definida en la configuración
    IMotorFactory factoria = ObtenerFactoria();
 
    // Instanciamos un motor a través de la factoría.
    // Fijémonos que únicamente tratamos con interfaces. En ningún momento
    // concretamos la clase con la que estamos trabajando
    IMotor motor = factoria.CreateInstance();
 
    // Finalmente, hacemos uso del motor a través de los métodos de la
    // interfaz IMotor.
    Console.WriteLine(motor.InyectarCombustible(20));
    Console.WriteLine(motor.ConsumirCombustible());
    Console.WriteLine(motor.RealizarExpansion());
    Console.WriteLine(motor.RealizarEscape());
    Console.ReadLine();
 
}
Patrón Abstract Factory (Factoría
Abstracta)
• La factoría abstracta va un paso más allá y extiende la funcionalidad
de Factory Method mediante la posibilidad de instanciar , en vez de
un objeto, un conjunto de objetos relacionados o de la misma familia.
Hasta ahora disponíamos de un método CreateInstance() que
generaba una instancia de un motor. La factoría abstracta contendrá,
en lugar de un único método, una colección de métodos que al ser
invocados instanciarán un objeto de una familia determinada. Este
patrón suele ser corriente, por ejemplo, en las conexiones a base de
datos, donde una misma factoría es capaz de crear tanto una
conexión (DbConnection) como una órden Sql (SqlCommand) para
distintas bases de datos. Por ejemplo:
// Creamos la factoría concreta a través de un parámetro
DbProviderFactory factoryOracle = DbProviderFactories.GetFactory("Oracle.DataAccess.Client");
 
// Instanciamos dos objetos distintos, pero de la misma familia (Oracle)
DbConnection conexionOracle = factoryOracle.CreateConnection();
DbDataAdapter adapterOracle = factoryOracle.CreateDataAdapter();
 
 
// Creamos la factoría concreta a través de un parámetro
DbProviderFactory factorySql = DbProviderFactories.GetFactory("System.Data.SqlClient");
 
// Instanciamos dos objetos distintos, pero de la misma familia (SQL Server)
DbConnection conexionSql = factorySql.CreateConnection();
DbDataAdapter adapterSql = factorySql.CreateDataAdapter();

Como observamos, las interfaces DbConnection y DbDataAdapter efectúan las mismas operaciones sobre una base de
datos Oracle y SQL Server. Las factorías proporcionan estos elementos, junto a algunos más. Por lo tanto, la diferencia
fundamental entre Factory Method y Abstract Factory radica en que el segundo patrón se centra en familias
completas de objetos en lugar de hacerlo con una única clase.
Usando este tipo de factorías es posible ampliar la funcionalidad de nuestras clases respetando el Principio
Abierto/Cerrado. El nombre de la clase de la nueva factoría (en el ejemplo
anterior Oracle.DataAccess.Client y System.Data.SqlClient) permitirá a la factoría abstracta instanciar nuevas factorías a
medida que las nuevas familias de objetos se vayan añadiendo.
• ¿Cuándo utilizar este patron? Ejemplos reales
• Ya hemos visto un ejemplo real de factoría abstracta: la
clase DbProviderFactory, que proporciona factorías para diversas
familias de bases de datos y permiten crear desde conexiones hasta
adaptadores de datos (DataAdapter).
• Este patrón se utiliza también a la hora de definir elementos de
interfaces gráficas, tales como botones, paneles, etc. Dependiendo del
motor gráfico que se vaya utilizar. Por ejemplo, se utilizaría una factoría
para elementos gráficos de Gtk, otra para elementos gráficos de KDE,
otra para elementos gráficos de xfce…
• Si se cuenta con varios entornos (producción, desarrollo, pruebas)
también puede ser útil para, mediante el fichero de configuración,
instanciar determinados objetos dependiendo de éste (por ejemplo,
para realizar el mocking de las pruebas unitarias).
PATRON BUILDER
• Objetivo: “Separar la construcción de un objeto complejo de su
representación, de modo que el mismo proceso de construcción
pueda crear representaciones diferentes.”
• Hablando en plata, el patrón Builder es un patrón creacional cuyo objetivo es instanciar objetos
complejos que generalmente están compuestos por varios elementos y que admiten diversas
configuraciones. Cuando hablamos de “construcción” nos referimos al proceso, mientras que
cuando hablamos de “representación” nos estaremos refiriendo a los datos que componen el
objeto. Se encargará, por tanto, de encapsular todo el proceso de generación de modo que
únicamente necesite los detalles necesarios para “personalizar” el objeto, devolviendo como
resultado una instancia del objeto complejo que deseamos construir. Es un patrón fuertemente
ligado a otro, el patrón estructural Composite.
Vehiculo v = new Vehiculo();
v.NumPuertas = 5; Como vemos, la lógica de nuestro programa construye un
v.Matricula = "1034 CAA"; vehículo compuesto de muchas partes (de hecho, podríamos
v.Faros = new Faro[4];
v.Faros[0] = new Faro(TipoFaro.Xenon); seguir añadiendo detalles) de forma secuencial. El
v.Faros[1] = new Faro(TipoFaro.Xenon); patrón Builder se encargará de encapsular todo este proceso
v.Faros[2] = new Faro(TipoFaro.Lexus);
v.Faros[3] = new Faro(TipoFaro.Lexus); haciendo que, mediante la obtención de estos detalles, el
v.Color = "Rojo"; proceso de generación de este objeto sea transparente para
v.Motor = new Motor(TipoMotor.Gasolina);
v.Motor.Capacidad = 2200; quien lo solicita.
v.Motor.Valvulas = 12;
DirectorConstruccion director = new DirectorConstruccion (new ConstructorFordFiestaSportEdition());
Vehiculo v = director.ConstruirVehiculo();
• El resultado a nivel computacional será más o menos el mismo, ya
que el proceso de “ensamblado” debe realizarse de todos modos. La
diferencia radica en que la lógica del programa no necesita
saber cómo ensamblar el objeto, sino únicamente aquellas piezas que
quiere que éste disponga. Si vas a comprar un vehículo, no le indicarás
al vendedor el proceso de fabricación de éste paso a paso: él
únicamente debe proporcionarte un vehículo que se ajuste a las
características que tú le solicitas, dejándole a él los detalles de cómo
el vehículo es construido.
• Elementos del patrón
• Utilizaremos el ejemplo de los vehículos para entender cómo funciona este patrón.
Comenzaremos por el final: el producto que queremos obtener. Se trata del objeto complejo que
queremos obtener, que suponemos que estará compuesto por un buen número de elementos.
Imaginemos que queremos obtener un vehículo y que su estructura es la siguiente:
// Tipo de rueda: diámetro, llanta y neumático
public class Rueda // Motor diesel, que implementará la interfaz IMotor
{ public class MotorDiesel : IMotor
    public int Diametro { get; set; } {
    public string Llanta { get; set; }     #region IMotor Members
 
    public string Neumatico { get; set; }
    public string ConsumirCombustible()
}
    {
// Tipo de carrocería
        return RealizarCombustion();
public class Carroceria
    }
{
 
    public bool HabitaculoReforzado { get; set; }
    public string InyectarCombustible(int cantidad)
    public string Material { get; set; }
    {
    public string TipoCarroceria { get; set; }
        return string.Format("MotorDiesel: Inyectados {0} ml. de Gasoil.", cantidad);
}
    }
// Interfaz que expone las propiedades del motor
 
public interface IMotor     public string RealizarEscape()
{     {
    string ConsumirCombustible();         return "MotorDiesel: Realizado escape de gases";
    string InyectarCombustible(int cantidad);     }
    string RealizarEscape();  
    string RealizarExpansion();     public string RealizarExpansion()
}     {
        return "MotorDiesel: Realizada expansion";
    }
 
    #endregion
 
    private string RealizarCombustion()
    {
        return "MotorDiesel: Realizada combustion del Gasoil";
    }
}
• Finalmente, la clase que simboliza el vehículo estará formada por los elementos anteriores más algún atributo más. El
producto, como podemos imaginar, será el elemento final una vez haya sido correctamente configurado. Marquémonos
como objetivo la construcción del siguiente vehículo: Audi A3 Sportback. Este vehículo constará de llantas de aluminio de
17cm y neumáticos Michelín, color plata cromado, cierre centralizado y dirección asistida, con una carrocería reforzada de
fibra de carbono. Ya tenemos el objetivo. Ahora necesitamos un constructor (builder) que lo construya por nosotros.
public class Vehiculo
{
    public bool CierreCentralizado { get; set; }
    public string Color { get; set; }
    public bool DireccionAsistida { get; set; }
    public string Marca { get; set; }
    public string Modelo { get; set; }
    public IMotor Motor { get; set; }
    public Carroceria TipoCarroceria { get; set; }
    public Rueda TipoRuedas { get; set; }
    public string GetPrestaciones()
    {
        StringBuilder sb = new StringBuilder();
        string nl = Environment.NewLine;
 
        sb.Append("El presente vehiculo es un ").Append(Marca).Append(" ").Append(Modelo);
        sb.Append(" estilo ").Append(TipoCarroceria.TipoCarroceria).Append(nl);
        sb.Append("Color: ").Append(Color).Append(nl);
        sb.Append(DireccionAsistida ? "Con " : "Sin ").Append("direccion asistida").Append(nl);
        sb.Append(CierreCentralizado ? "Con " : "Sin ").Append("cierre centralizado").Append(nl);
        sb.Append("Carroceria de ").Append(TipoCarroceria.Material);
        sb.Append(TipoCarroceria.HabitaculoReforzado ? " con " : " sin ").Append("el habitaculo reforzado").Append(nl);
        sb.Append("Ruedas con llantas ").Append(TipoRuedas.Llanta).Append(" de ").Append(TipoRuedas.Diametro).Append(" cm").Append(nl);
        sb.Append("Neumaticos ").Append(TipoRuedas.Neumatico);
        sb.Append("Respuesta del motor: ").Append(Motor.InyectarCombustible(100));
        return sb.ToString();
    }
}
• La clase Builder y los constructores concretos
• La clase constructora será la encargada de construir nuestro objeto. Sin embargo, esta clase no
debe preocuparse de cómo debe construir el producto, sino únicamente de qué partes han de
construirse. Al igual que en una fábrica de ensamblaje, el peón debe centrarse en una tarea
concreta de construcción, dejando el proceso del ensamblaje ordenado para otros
trabajadores.
• Sin embargo, antes de ponernos a codificar el contenido de nuestro constructor, es preciso
pensar un poco en la (más que probable) posibilidad de que otro cliente decida, en algún
momento dado, un vehículo diferente. Por ello, definiremos una interfaz a la que todo
constructor deberá ceñirse para asegurar la compatibilidad del proceso. Todos los constructores
de coches deberán saber añadir ruedas, carrocería o motor, por lo que crearemos una
interfaz IVehiculoBuilder que implemente todas estas operaciones. Recordemos que las
operaciones deben ceñirse al proceso de construir las partes, nunca de cómo combinarlas (ni
en qué orden.
• Otra posibilidad, en lugar de utilizar una interfaz, será la de hacer uso de una clase que defina la
funcionalidad común y declare como abstractos los métodos que deberá implementar el
constructor concreto para cada coche en particular. Ciñámonos a esta segunda opción y
creemos la clase VehiculoBuilder, que será como sigue:
• La interfaz tendrá un aspecto como el siguiente:
public class A3SportbackBuilder : VehiculoBuilder
public abstract class VehiculoBuilder {
{
    public override void DefinirVehiculo()
    // Declaramos la referencia del producto a
    {
construir
        v = new Vehiculo();
    protected Vehiculo v;         v.Marca = "Audi";
          v.Modelo = "A3 Sportback";
    // Declaramos el método que recuperará el objeto     }

    public Vehiculo GetVehiculo()


    // Método que construirá las ruedas
    {     public override void ConstruirRuedas()
    {
        return v;
        v.TipoRuedas = new Rueda();
    }
        v.TipoRuedas.Diametro = 17;
          v.TipoRuedas.Llanta = "aluminio";
    #region Métodos Abstractos         v.TipoRuedas.Neumatico = "Michelin";
    }
 
    // Método que construirá el motor
    public abstract void DefinirVehiculo();
    public override void ConstruirMotor()
    public abstract void ConstruirRuedas();     {
    public abstract void ConstruirHabitaculo();         v.Motor = new MotorDiesel();
    }
    public abstract void ConstruirMotor();
    // Método que construirá el habitaculo
    public abstract void DefinirExtras();
    public override void ConstruirHabitaculo()
      {
    #endregion         v.TipoCarroceria = new Carroceria();
}         v.TipoCarroceria.TipoCarroceria = "deportivo";
Lo que el constructor debe saber hacer, por lo tanto, es definir marca y modelo,         v.TipoCarroceria.HabitaculoReforzado = true;
        v.TipoCarroceria.Material = "fibra de carbono";
construir las ruedas, el habitáculo, el motor y añadir los extras. También debe contar         v.Color = "plata cromado";
con la instancia del vehículo que debe devolver, al igual que un método para poder     }

devolverlo.     public override void DefinirExtras()


    {
Una vez que hemos definido de forma genérica qué operaciones debe realizar el         v.CierreCentralizado = true;
constructor, codificaremos una clase A3SportbackBuilder que herede         v.DireccionAsistida = true;
    }
de VehiculoBuilder y que implemente el código de los métodos abstractos, de modo }
que proporcione una instancia de un Audi A3 Sportback Edition:
public class CitroenXsaraBuilder : VehiculoBuilder
{

• Si otro cliente llegara y nos pidiera     public override void DefinirVehiculo()


    {

un Citroen Xsara Picasso negro con         v = new Vehiculo();


        v.Marca = "Citroen";
        v.Modelo = "Xsara Picasso";
llantas de 15cm estándar,     }
    //
neumáticos Firestone y sin extras, Método que construirá las ruedas
    public override void ConstruirRuedas()

codificaríamos una nueva clase que     {


        v.TipoRuedas = new Rueda();
también herede         v.TipoRuedas.Diametro = 15;
        v.TipoRuedas.Llanta = "hierro";

de VehiculoBuilder y que         v.TipoRuedas.Neumatico = "Firestone";


    }
    public
implemente de una forma distinta     {
override void ConstruirMotor()

todos los pasos necesarios para         v.Motor = new MotorDiesel();


    }

construir el vehículo.     // Método que construirá el habitaculo


    public override void ConstruirHabitaculo()
    {
        v.TipoCarroceria = new Carroceria();
        v.TipoCarroceria.TipoCarroceria =
Recordar que estamos construyendo los "monovolumen";
componentes, el orden de ensamblado y las         v.TipoCarroceria.HabitaculoReforzado = false;
        v.TipoCarroceria.Material = "acero";
verificaciones no son responsabilidad de estos         v.Color = "negro";
    }
constructores.
    public override void DefinirExtras()
    {
        v.CierreCentralizado = false;
        v.DireccionAsistida = false;
    }
}
Cada Modelo de coche, tendrá su builder
Concreto, que construirá los componentes
o partes del coche dejando la responsabilidad
Del ensamblado de los componentes a una clase
Denominada Directora.
La clase directora
Ahora que ya sabemos cómo generar las partes, es necesario saber cómo ensamblarlas. Esta operación no se
realizará en el constructor concreto de cada coche, sino que se creará una nueva clase, denominada Directora,
que se encargará de toda la lógica del ensamblado, lo cual incluye orden, validaciones, comprobaciones, etc.
Nuestra clase directora, por tanto, no sabrá construir las partes, tarea que delegará en los constructores
(builders concretos), sino que sabrá cómo construir el todo a partir de éstas. Lo normal es que la clase directora
reciba un único parámetro, de tipo VehiculoConstructor (es decir, del constructor genérico, la clase abstracta) y
genere las partes invocando los métodos comunes (los métodos definidos en la interface o abstract), sin
necesidad de preocuparse de los detalles.
A la clase directora no le hace falta saber si está construyendo un Audi A3 o un Citroen Xsara, de hecho
inyectamos en la clase directoria el builder concreto. La clase directora debe saber que el chasis se monta antes
que las ruedas o que es necesario incluir dirección asistida en un modelo deportivo.
Por lo tanto, crearemos una clase directora cuyo método principal será ConstruirVehiculo() y que constará de un
elemento VehiculoBuilder, que recibirá como parámetro, así:
public class VehiculoDirector
{
    private VehiculoBuilder builder;
 
    // Constructor que recibirá un Builder concreto y lo asociará al director
    public VehiculoDirector(VehiculoBuilder builder)
    {
        this.builder = builder;
    }
 
    public void ConstruirVehiculo()
    {
        // Construimos el vehiculo definiendo el orden del proceso
        builder.DefinirVehiculo();
        builder.ConstruirHabitaculo();
        builder.ConstruirMotor();
        builder.ConstruirRuedas();
        builder.DefinirExtras();
 
        // Se realizan comprobaciones y validaciones
        if ((builder.GetVehiculo().TipoCarroceria.TipoCarroceria == "deportivo") &&
            (builder.GetVehiculo().DireccionAsistida == false))
            throw new Exception("Error en el ensamblado: Un deportivo no puede carecer de dirección asistida");
    }
 
    public Vehiculo GetVehiculo()
    {
        return builder.GetVehiculo();
    }
}
Utilizando el patrón Builder
La utilización de este patrón, por lo tanto, consistirá en lo siguiente:
• Instanciar un nuevo director pasándole como parámetro el
constructor concreto que se encargará de construir las piezas.
• Indicarle al constructor que construya el objeto.
• Recuperar el objeto del director (que, a su vez, lo recupera del
constructor concreto).
• El siguiente código muestra cómo se usan dos directores que reciben
dos constructores concretos distintos para generar, a su vez, dos
vehículos distintos.
/ Definimos un director, pasándole un constructor de Audi como parámetro
VehiculoDirector directorAudi = new VehiculoDirector(new A3SportbackBuilder());
 
// El director construye el vehiculo, delegando en el constructor la tarea de
// creación de cada una de las piezas
directorAudi.ConstruirVehiculo();
 
// Obtenemos el vehículo directamente del director, aunque la instancia del
vehículo
// se encuentra en el constructor.
Vehiculo audiA3 = directorAudi.GetVehiculo();
 
// Repetimos el proceso con un constructor distinto.
VehiculoDirector directorCitroen = new VehiculoDirector(new
CitroenXsaraBuilder());
directorCitroen.ConstruirVehiculo();
Vehiculo citroen = directorCitroen.GetVehiculo();
 
// Mostramos por pantalla los dos vehiculos:
Console.WriteLine("PRIMER VEHICULO:" + Environment.NewLine);
Console.WriteLine(audiA3.GetPrestaciones());
 
Console.WriteLine("SEGUNDO VEHICULO:" + Environment.NewLine);
Console.WriteLine(citroen.GetPrestaciones());
 
Console.ReadLine();
¿Cuándo utilizar este patrón? Ejemplos reales
Este patrón es útil en alguno de los siguientes supuestos:
• Cuando el algoritmo para crear un objeto complejo puede independizarse de las partes que
componen el objeto y de cómo son ensambladas.
• Cuando el proceso de construcción debe permitir distintas representaciones (distintos
valores) para el objeto que se construye.
• Cuando el objeto a construir es complejo y sus distintas configuraciones son limitadas. En
caso de que necesitemos un objeto complejo pero cada una de sus partes deba ser
configurado de forma individual (en el ejemplo que nos ocupa, se trataría de definir cada
elemento “al gusto” del consumidor en lugar de objetos predefinidos), este patrón no será
una buena idea, ya que será necesario realizar el proceso de asignación de cada elemento
paso a paso.
• Como ejemplos reales, GoF ilustra su aplicación con un parser
RTF, en el que separa los algoritmos de procesamiento dependiendo del texto a transformar
(ASCII, TEX…). Puede verse el ejemplo aquí.
• Otro ejemplo puede ser la generación de distintos tipos de Sitemaps (Google, HTML…). El
ejemplo puede verse aquí.
PATRÓN PROTOTYPE

• Objetivo: “Especificar el tipo de objetos que se crearán utilizando una


instancia prototipada y crear nuevos objetos realizando copias de ese
prototipo.”
El concepto de este patrón es simple: en lugar de crear un objeto, se clona, es
decir, se realiza una copia exacta de otro objeto dado, denominado prototipo.
Entran en juego tres elementos:
• Cliente: clase que solicita al prototipo que se clone.
• IPrototipo: interfaz o clase abstracta que define la operación de clonado.
• PrototipoConcreto: implementa IPrototipo y su método Clone() para proceder
al clonado del objeto.
El proceso de clonado comienza instanciando una clase de forma habitual. Una
vez que disponemos de una instancia funcional, el resto de instancias se
generarán creando copias de la primera.
La forma de aplicar este patrón es simple:
• Se define una interfaz que expondrá el método utilizado para realizar el
clonado del objeto.
• Las clases que realicen el clonado utilizarán este método para esta operación.
Implementación del patrón: En .NET este proceso es sencillo, ya
que nos ofrece la interfaz ICloneable que expone el
public class Vehiculo : ICloneable método Clone(), método en el que habrá que codificar el
{
    public string Marca { get; set; } proceso de copia.
    public string Modelo { get; set; }
    public string Color { get; set; } Además de ofrecer el método Clone(), .NET también ofrece un
    public Rueda TipoRueda { get; set; }
    public Carroceria TipoCarroceria { get; set; }
método, MemberwiseClone(), que automáticamente realiza una
 
    public string VehiculoInfo()
copia del objeto por nosotros, evitándonos el proceso de copiar
    { elemento por elemento de forma manual.
        StringBuilder sb = new StringBuilder();
        sb.Append("Marca: ").Append(Marca).Append(Environment.NewLine);
        sb.Append("Modelo: ").Append(Modelo).Append(Environment.NewLine);
        sb.Append("Color: ").Append(Color).Append(Environment.NewLine);
        sb.Append("Ruedas: ").Append(TipoRueda.Llanta).Append(" ");
        sb.Append(TipoRueda.Diametro).Append(" ").Append(TipoRueda.Neumatico).Append(Environment.NewLine);
        sb.Append("Carroceria: ").Append(TipoCarroceria.HabitaculoReforzado).Append(" ");
        sb.Append(TipoCarroceria.TipoCarroceria).Append(" ").Append(TipoCarroceria.Material).Append(Environment.NewLine);
 
        return sb.ToString();
    }
 
    #region ICloneable Members
 
    public object Clone()
    {
        return this.MemberwiseClone();
    }
 
    #endregion
}
Vehiculo v = new Vehiculo();
 
v.Marca = "Peugeot";
v.Modelo = "306";
v.Color = "Negro";
public class Rueda  
{ v.TipoCarroceria = new Carroceria();
    public int Diametro { get; set; } v.TipoCarroceria.Material = "Acero";
    public string Llanta { get; set; } v.TipoCarroceria.HabitaculoReforzado = true;
    public string Neumatico { get; set; } v.TipoCarroceria.TipoCarroceria = "Monovolumen";
}  
v.TipoRueda = new Rueda();
public class Carroceria v.TipoRueda.Neumatico = "Bridgestone";
{ v.TipoRueda.Llanta = "Aluminio";
    public bool HabitaculoReforzado { get; set; } v.TipoRueda.Diametro = 17;
    public string Material { get; set; }  
    public string TipoCarroceria { get; set; } Vehiculo v2 = v.Clone() as Vehiculo;
}  
Console.WriteLine(v.VehiculoInfo());
Console.WriteLine("--------------------------------------"
);
Console.WriteLine(v2.VehiculoInfo());
 
Console.ReadLine();
Clonación superficial y clonación profunda
• Cuando invocamos el método MemberwiseClone() observamos que en
su descripción indicaba que se realizaba una clonación shallow o
superficial. Esto significa que el clonado se realiza a nivel de bits, por lo
que los objetos contenidos dentro del objeto a clonar no se clonarán
también, sino que se clonará únicamente la referencia del objeto. Por
lo tanto, ambos objetos clonados apuntarán al mismo objeto. Esto es
lo que se conoce como clonación superficial. El proceso por el cual se
clonan los objetos incluidos en el objeto a clonar en lugar de copiar
sus referencias se denomina clonación profunda.
Por lo tanto si deseamos realizar una clonación
profunda, deberemos realizarla de forma manual.
Por ejemplo, haciendo que las clases dependientes
del objeto a clonar puedan a su vez ser clonados:
public class Rueda : ICloneable
{
Una vez hecho esto, añadiremos el siguiente código a nuestra clase principal para realizar el
    public int Diametro { get; set; } siguiente proceso:
    public string Llanta { get; set; } •Recorrer las propiedades del objeto que implementan la interfaz ICloneable
    public string Neumatico { get; set; }
 
•Extraer el nombre de la propiedad (por ejemplo Rueda)
    #region ICloneable Members •Invocar su método Clone() mediante Reflection y guardar la referencia al nuevo objeto.
  •Hacer que la referencia del objeto clonado (Vehiculo) apunte al nuevo objeto que hemos clonado
    public object Clone()
    { mediante reflection (Rueda)
        return this.MemberwiseClone();
    }
 
    #endregion
}
 
public class Carroceria : ICloneable
{
    public bool HabitaculoReforzado { get; set; }
    public string Material { get; set; }
    public string TipoCarroceria { get; set; }
 
    #region ICloneable Members
 
    public object Clone()
    {
        return this.MemberwiseClone();
    }
 
    #endregion
}
public object Clone()
{
    // Obtenermos una copia superficial del objeto actual
    object copia = this.MemberwiseClone();
 
    // Recorremos las propiedades del objeto buscando elementos clonables.
    // En caso de encontrar un objeto clonable, realizamos una copia de dicho elemento
    var propiedadesClonables = this.GetType().GetProperties().Where(p => p.PropertyType.GetInterfaces().Contains( typeof(ICloneable)));
    foreach (var propiedad in propiedadesClonables)
    {
        // Obtenemos el nombre de la propiedad (p.e. "TipoRueda")
        var nombrePropiedad = propiedad.Name;
         
        // Localizamos el método Clone() de la propiedad (TipoRueda.Clone()) y lo
        // invocamos mediante reflection, almacenando el objeto resultante en una variable
        MethodInfo metodoClone = propiedad.PropertyType.GetMethod("Clone");
        var objetoCopia = metodoClone.Invoke(propiedad.GetValue(copia), null);
 
        // Obtenemos una referencia a la propiedad del objeto clonado (Vehiculo2.TipoRueda)
        PropertyInfo referenciaCopia = this.GetType().GetProperty(nombrePropiedad, BindingFlags.Public | BindingFlags.Instance);
 
        // Asignamos el valor del objeto clonado a la referencia (Vehiculo2.TipoRueda = Rueda2)
        referenciaCopia.SetValue(copia, objetoCopia, null);
    }
 
    return copia;
}
• ¿Cuándo utilizar este patrón? Ejemplos reales
• Este patrón está indicado en los casos en los que el coste de generar una nueva instancia sean
altos en comparación al coste de realizar una copia de una instancia ya existente. Por ejemplo,
imaginemos que tenemos una clase que se encarga de almacenar datos de una sesión web. Al
instanciar esta clase, el objeto se comunica con un servidor externo para realizar un proceso de
autenticación mediante unas credenciales. Este proceso es costoso, por lo que si a lo largo de la
ejecución del programa fuese necesario instanciar un nuevo objeto con los mismos datos, el
proceso de instanciación requerirá consumir una gran cantidad de recursos. Sería más sencillo
realizar una copia exacta del objeto anterior, evitando de este modo acceder a un servidor externo
para rellenar el objeto actual.
• Podemos sustituir el proceso de conectar a otro servidor por cualquier otro proceso de alto coste
computacional, como operaciones de acceso de base de datos o procesamiento de algoritmos
complejos. Siempre que necesitemos instanciar un objeto cuyos datos han sido obtenidos
previamente podemos recurrir a este patrón para evitar el proceso de instanciado realizando una
copia de un objeto existente.
• Otro posible escenario en el que este patrón es útil puede ser cuando sea necesario “salvar” el
estado de un objeto en un determinado momento realizando una copia del mismo.
• Un escenario real en el que se suele utilizar este patrón suele ser el de la clonación de figuras en
programación 2D/3D, así como el de paletas de colores.
PATRÓN SINGLETON
• Objetivo: Asegurarse de que una clase tiene una única instancia,
proporcionando acceso global a ella.”
• Hay clases que deben instanciarse una única vez. El acceso a un sistema de
archivos, a la cola de impresión o al gestor de ventanas del sistema operativo
debería realizarse por un único objeto, siendo labor de la propia clase el controlar
que la instancia sea única. Por norma general, esta clase será accesible de forma
global, y el proceso de instanciado no suele requerir parámetros.
• Como podemos observar en el diagrama, nuestra clase Singleton constará al
menos con dos métodos:
• Un método Instance() de carácter estático (método de clase) que se encargará de
instanciar la clase.
• Un constructor privado que evitará que se creen nuevos objetos mediante new(),
haciendo que el método Instance() sea el único que puede generar la instancia.
• Implementación del patrón:
• Implementar este patrón es simple: dado que el constructor es
privado, tan sólo podrá ser invocado desde el interior de la propia
clase. Por lo tanto, el esquema del patrón se reduce a la siguiente:
• La clase Singleton contará con un atributo de la propia clase Singleton,
de carácter privado.
• El constructor (privado) se encargará de construir el objeto.
• El método estático Instance() realizará dos operaciones:
• Comprobar si el atributo es null. En ese caso, se invocará al constructor. En
caso contrario, se devolverá el objeto existente.
• En código, será tan simple como hacer lo siguiente:
public class Singleton
{
    // Declaramos un atributo del mismo tipo de la clase con carácter estático
    private static Singleton _instancia = null;
 
    public string Nombre { get; set; }
    public DateTime HoraArranque { get; set; }
 
    // Constructor privado. Únicamente puede ser invocado desde el interior
    // de la propia clase
    private Singleton()
    {
        Nombre = "Patrón Singleton";
        HoraArranque = DateTime.Now;
    }
 
    // Property de solo lectura
    public static Singleton Instance
    {
        get
        {
            // Si el singleton no ha sido creado previamente, se instancia.
            // En caso contrario, se devolvera el que haya sido creado previamente
            if (_instancia == null)
                _instancia = new Singleton();
 
            // Se devuelve la instancia
            return _instancia;
        }
    }
}
• Usamos un pequeño programa para comprobar su funcionamiento,
en el que se instanciará el Singleton, se hará una pausa de tres
segundos y se intentará crear una nueva instancia (llamando a la
propiedad Instance, ya que recordemos que el constructor es
privado). Si se trata de la misma instancia, se mostrará exactamente la
misma hora:
static void Main(string[] args)
 {
     // Instanciamos el Singleton
     Singleton s = Singleton.Instance;
 
     // Hacemos una pausa de tres segundos
     Thread.Sleep(3000);
 
     // Intentamos instanciar un segundo Singleton
     Singleton s2 = Singleton.Instance;
 
     // Comprobamos que ambos objetos son referencias a la misma
     // instancia, que es única
     Console.WriteLine(string.Format("Instancia {0} creada a las {1}",
         s.Nombre, s.HoraArranque.ToLongTimeString()));
     Console.WriteLine(string.Format("Instancia {0} creada a las {1}",
         s2.Nombre, s2.HoraArranque.ToLongTimeString()));
 
     Console.ReadLine();
 }
• ¿Cuándo utilizar este patrón? Ejemplos reales
• La existencia de este patrón es relativamente clara: debe utilizarse
cuando nuestra aplicación precise que una clase se instancie una
única vez. Siempre que exista un objeto de carácter global, que
apenas cambie con el tiempo, será susceptible de ser diseñado
mediante un patrón Singleton.
• Ejemplos reales de utilización de patrones Singleton podrían ser
utilidades de Logging (no nos interesa que más de una instancia
escriba en un log a la vez) y utilidades de configuración del sistema,
así como clases encargadas de realizar el cacheo o el balanceo de
carga. Es importante ser conscientes de que Singleton no es un patrón
del que se deba abusar, puesto que su funcionalidad se encierra en un
ámbito de aplicación muy limitado.
PATRONES
ESTRUCTURALES

Estos patrones están pensados más en como crear clases nuevas sin
modificar las existentes O/C
PATRÓN ADAPTER (WRAPPER)
• Objetivo: Convertir la interfaz de una clase en otra interfaz que el cliente
espera. Adapter consigue que trabajen juntas clases que de otro modo no
podrían.
• El patrón Adapter nos abre el camino hacia el segundo grupo de patrones
propuestos por el Gang of Four: los patrones estructurales. Si bien los
patrones de creación definían la forma en la que los objetos son
instanciados, los patrones estructurales se basan en la forma en la que un
conjunto de clases se relacionan entre sí para proporcionar una funcionalidad
compleja, proporcionando una estructura para conseguir lograr ese objetivo.
• La filosofía de Adapter, al igual que vimos con Prototype, es tan simple como
autoexplicativa: establecer una capa intermedia que permita comunicarse a
dos clases que de otro modo no podrían hacerlo, realizando
una adaptación de la interfaz de la clase que proporciona el servicio a la que
la solicita.
• Representándolo de una forma visual, imaginemos que nuestro objeto
pertenece a la clase Taladro y requiere hacer uso del método Flujo110V() de
una clase que implemente la interfaz IEnchufeIngles. Por tanto, nuestro
taladro está preparado para hacer uso de esa interfaz y espera recibir como
valor de retorno un flujo con una diferencia de potencial de 110V
• Sin embargo, resulta que la clase de la que disponemos en el otro
extremo no implementa esta interfaz, sino otra
llamada IEnchufeEuropeo() que dispone de un método capaz de
devolver a nuestro taladro un flujo de 220V, cuyo nombre
es Flujo220V(). La funcionalidad es parecida, pero no la esperada, y la
interfaz que el taladro espera utilizar no es compatible con el
elemento del subsistema. Nos encontramos, por tanto, con un claro
problema de compatibilidad.
• Para que nuestro taladro pueda comunicarse con IEnchufeEuropeo, será
necesario modificar uno de los dos extremos para que la interfaz de
comunicación coincida, pero si hiciéramos esto, nuevamente estaríamos
rompiendo el principio abierto/cerrado del que hablamos con anterioridad,
amén de que cambiando esta interfaz haríamos que de repente dejasen de
compilar todas aquellas clases que la estuvieran utilizando hasta el momento.
• La solución adecuada consistirá en adaptar los requerimientos de la interfaz de
la clase cliente (taladro) a los servicios que la clase servidora (sistema eléctrico
europeo) puede ofrecer. Hablando en plata, y tal como indica el propio nombre
del patrón, necesitaremos un adaptador que haga coincidir la entrada de un
elemento con la salida del otro. Este será el objetivo del patrón Adapter
• Por lo tanto, cuando nos encontremos con un problema similar a este,
lo más adecuado será codificar una nueva clase que implemente la
interfaz original (IEnchufeIngles) y que posea una propiedad cuyo tipo
será el de la clase que se pretende adaptar. En este caso, nuestra
clase adaptador contendrá una referencia a una instancia de una clase
que implemente IEnchufeEuropeo. De este modo, nuestro taladro
hará una llamada a la clase que espera (IEnchufeIngles.Flujo110V()) y
de forma interna se invocará el método Flujo220V() mediante la
instancia de EnchufeEuropeo.
• Codificando un Adaptador
• Un adaptador no sólo se encarga de transformar una interfaz en otra:
también puede realizar otro tipo de operaciones, principalmente de
transformación. En el ejemplo de los enchufes, además de transformar
una interfaz en otra (los polos del enchufe), nuestro adaptador podía
también realizar otras operaciones, como por ejemplo transformar la
diferencia de potencial del flujo de salida de 220 a 110, ya que de lo
contrario correríamos el riesgo de quemar nuestro dispositivo.
• Comencemos proporcionando las
interfaces IEnchufeIngles e IEnchufeEuropeo y dos clases que las
implementen:
public interface IEnchufeIngles
{
    // Devuelve un array de enteros con un voltaje de unos 110V
    int[] Flujo110V();
 
    // Devuelve el numero de bornes del enchufe
    int getNumeroBornes(); public class EnchufeBritanico : IEnchufeIngles
} {
    #region IEnchufeIngles Members
 
    // Devuelve un array con voltajes en distintos momentos
    public int[] Flujo110V()
    {
        int[] arrayFlujo = new int[100];
        Random r = new Random();
        for (int i = 0; i < arrayFlujo.Length; i++)
        {
            // Calculamos la fluctuacion del voltaje
            int fluctuacion = r.Next(100) > 50 ? 1 : -1;    // Positiva o negativa
            fluctuacion = fluctuacion * (r.Next(7) + 1);    // El valor fluctuara entre -7 y +7
 
            // Valor total entre 103 y 117V
            arrayFlujo[i] = fluctuacion + 110;
        }
 
        return arrayFlujo;
    }
 
    // Devuelve el numero de bornes del enchufe
    public int getNumeroBornes()
    {
        return 3;
    }
 
    #endregion
}
public interface IEnchufeEuropeo
{
    // Devuelve un array de enteros con un voltaje de unos 220V
    int[] Flujo220V();
 
    // Devuelve el numero de bornes del enchufe
    int getNumeroBornes(); public class EnchufeEspanol : IEnchufeEuropeo
} {
    #region IEnchufeEuropeo Members
 
    // Devuelve un array con voltajes en distintos momentos
    public int[] Flujo220V()
    {
        int[] arrayFlujo = new int[100];
        Random r = new Random();
        for (int i = 0; i < arrayFlujo.Length; i++)
        {
            // Calculamos la fluctuacion del voltaje
            int fluctuacion = r.Next(100) > 50 ? 1 : -1;    // Positiva o negativa
            fluctuacion = fluctuacion * (r.Next(10) + 1);    // El valor fluctuara entre -0 y +10
 
            // Valor total entre 210 y 230V
            arrayFlujo[i] = fluctuacion + 220;
        }
 
        return arrayFlujo;
    }
 
    // Devuelve el numero de bornes del enchufe
    public int getNumeroBornes()
    {
        return 2;
    }
 
    #endregion
Ahora codificaremos nuestra clase Taladro, que posee un
enchufe inglés (es decir, posee una referencia a una
interfaz IEnchufeIngles) para recibir la alimentación:

public class Taladro


{
    // Enchufe del taladro
    private IEnchufeIngles enchufe;
 
    // Constructor a traves del cual se inyecta el enchufe
    public Taladro(IEnchufeIngles enchufeTaladro)
    {
        this.enchufe = enchufeTaladro;
    }
 
    public void Encender()
    {
        // Obtenemos la alimentación a través de la interfaz.
        // Recordemos que nuestro enchufe requiere una alimentacion de 110V
        int[] voltaje100ms = enchufe.Flujo110V();
 
        // Mostramos por pantalla el resultado.
        for (int i = 0; i < voltaje100ms.Length; i++)
            Console.WriteLine("El taladro esta funcionando con voltaje de " + voltaje100ms[i] +" Voltios");
    }
}
Lo ideal sería utilizar la clase EnchufeBritanico, que es lo que
nuestro taladro espera.
// Instanciamos enchufe y taladro
IEnchufeIngles enchufe = new EnchufeBritanico();
Taladro taladro = new Taladro(enchufe);
 
// Encendemos el taladro
taladro.Encender();
 
Console.ReadLine(); Sin embargo, recordemos que el patrón Adapter no tiene sentido en este escenario, sino cuando el
objeto del que disponemos no cumple con la interfaz esperada, es decir: en nuestro sistema, la
clase EnchufeBritanico no existe. La clase del subsistema al que necesitamos conectarnos no
implementa la interfaz IEnchufeBritanico, sino que se trata de un objeto de la
clase EnchufeEspanol. La situación, por lo tanto, es esta:

// Instanciamos enchufe y taladro


IEnchufeEuropeo enchufe = new EnchufeEspanol(); Lo cual nos daría un clarísimo error de compilación, ya que
Taladro taladro = new Taladro(enchufe); nuestro taladro espera un enchufe inglés.
 
// Encendemos el taladro
taladro.Encender();
// Implementamos la interfaz que espera recibir nuestra clase cliente Por lo tanto, crearemos una clase
public class AdapterInglesEuropeo : IEnchufeIngles adaptador (¡por fin!) que cumpla los
{
    // Declaramos una referencia de la clase o interfaz a la que queremos conectarnos preceptos que vimos previamente:
    private IEnchufeEuropeo enchufe; •Implementa la
 
    // El constructor del adaptador recibirá como parámetro el objeto al que se quiere interfaz IEnchufeIngles para ser
    // adaptar nuestro cliente. compatible con la clase Taladro.
    public AdapterInglesEuropeo(IEnchufeEuropeo enchufe)
    { •Incluya una referencia a
        this.enchufe = enchufe; un IEnchufeEuropeo
    }
    #region IEnchufeIngles Members •Implemente los
 
    // Invocamos los métodos de la interfaz servidora, transformando los datos para que pueda
métodos IEnchufeIngles invocando
    // manejarlos la clase cliente. los métodos adecuados
    public int[] Flujo110V()
    {
de IEnchufeEuropeo y realizando las
        // Invocamos el método de la interfaz incompatible operaciones de transformación
        int[] voltajes220 = enchufe.Flujo220V();
 
adecuadas.
        // Realizamos la adaptacion Un ejemplo sería el siguiente:
        int[] voltajes110 = new int[voltajes220.Length];
 
        for (int i = 0; i < voltajes220.Length; i++)
            voltajes110[i] = (int)(voltajes220[i] / 2);
 
        // Devolvemos el resultado adaptado, que es el que espera el cliente
        return voltajes110;
    }
 
    public int getNumeroBornes()
    {
        return enchufe.getNumeroBornes() - 1;
    }
    #endregion
Finalmente, instanciamos un enchufe español y usamos el adaptador
para hacer que le sirva a nuestro taladro:
// Instanciamos el enchufe español, que es el que existe en nuestro país
IEnchufeEuropeo enchufeEuropeo = new EnchufeEspanol();
 
// Instanciamos el adaptador pasándole el enchufe español como parámetro
IEnchufeIngles adaptador = new AdapterInglesEuropeo(enchufeEuropeo);
 
// Creamos el taladro pasándole nuestro adaptador
Taladro taladro = new Taladro(adaptador);
 
// Encendemos el taladro
taladro.Encender();
Como detalle, debemos fijarnos en que tanto la clase cliente como la adaptada ignoran
completamente su mutua existencia. Ambas clases están desacopladas por medio de esta
clase Adaptador, por lo que por norma general es un patrón que sirve como ejemplo
perfecto de buenas prácticas de programación.
Más adelante aprenderemos algo acerca de un patrón parecido y muy relacionado: el
patrón Facade o Fachada, que más que adaptar, establece una capa o Wrapper de un
conjunto de clases e interfaces concentrando un conjunto de llamadas.
• ¿Cuándo utilizar este patrón? Ejemplos reales
• El escenario de este patrón es también bastante claro. Se utilizará en los
casos en los que sea necesario utilizar una clase cuya interfaz no se adapte
a los requerimientos de otra clase cliente. Podemos ver algunos ejemplos
reales cuando realizamos transformaciones entre enumeraciones e
iteradores, arrays y listas, etc.
• El lenguaje Java, por ejemplo, ofrece los siguientes usos del
patrón Adapter:
• java.util.Arrays#asList()
• java.io.InputStreamReader(InputStream) (devuelve un Reader)
• java.io.OutputStreamWriter(OutputStream) (devuelve un Writer)
• javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
• javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()
USRobots y el patrón Adapter
En nuestra compañía CoolCorp, estamos desarrollando un software
personalizado para controlar robots. Los robots no los construye
nuestra compañía, si no que se los compramos a USRobots.
• Los robots que nos proporcionan tienen su propia interface de
comunicaciones. Es la siguiente:
interface USRobotsInterface Un ejemplo de implementación de un robot
{ de USRobots sería el siguiente:
float CurrentSpeedInMilesPerHour { get; set; }
void EnablePartialFirstLawMode();
void Jump(float feet);
}
class USRobot:USRobotsInterface
{
private float CurrentSpeed; El problema que tenemos, es que nuestra compañía vende el
public float CurrentSpeedInMilesPerHour software en España. Los clientes que van a trabajar con los
{
get { return CurrentSpeed; } robots, trabajan en Km/h y metros. Los robots de USRobots,
set { CurrentSpeed = value;} compañía estadounidense, utilizan un extraño sistema métrico
} midiendo la velocidad en millas por hora y la altura en pies.
public USRobot()
Además debido a la legislación europea, los robots no pueden
{ modificar la primera ley de la robótica, algo que sí está
this.CurrentSpeed = 0; permitido en EE.UU.
} Así que en este caso, no podemos utilizar la interface
public void EnablePartialFirstLawMode() proporcionada, porque es incompatible con nuestros
{ requisitos.
Console.WriteLine("Partial first law enabled");
}

public void Jump(float feet)


{
Console.WriteLine("Jump !!");
}
}
Solución con el patrón Adapter
Está claro que los requisitos de nuestra aplicación nos obligan a hacer cambios. La solución chapucera sería la
de instanciar objetos USRobot allí dónde los necesitemos. Cada vez que llamemos a uno de los métodos de
USRobot, hacemos la conversión de unidades y listo.
El problema de este enfoque es que estaríamos dependiendo de una entidad externa, que no controlamos. Si
USRobots actualiza sus implementaciones, añadiendo métodos o cambiando tipos, nosotros tendríamos que
modificar una gran cantidad de código. Por no hablar de que estaremos incumpliendo el principio DRY (Don't
Repeat Yourself).
Es mejor decidir qué es lo que necesitamos y encapsular USRobot para usarlo desde un único punto. Es decir,
vamos a seguir el principio de encapsular lo que puede variar. Por tanto, pensando en nuestras necesidades,
tendríamos la siguiente interface:
interface CoolCorpInterface
{
float CurrentSpeedInKilometersPerHour { get; set; }
void Jump(float meters);
}

Todos los robots con los que trabajemos, implementarán dicha interface, ya que es la que mejor se adapta a
nuestras necesidades. Ahora solo tenemos que desarrollar el adaptador en si, que en este caso tendrá el
siguiente código:
Como se puede ver, nuestro CoolCorpRobot implementa
class CoolCorpRobot:CoolCorpInterface
{
la interface que hemos definido antes. En el
private USRobot robot; constructor, creamos un objeto USRobot, que al
public CoolCorpRobot() final es el que realiza las operaciones. La clase
{ no implementa el método EnablePartialFirstLawMode
this.robot = new USRobot(); porque no lo necesitamos.
} Y ya está. Para usar el adaptador, bastará con
public float CurrentSpeedInKilometersPerHour utilizar algo similar a esto:
{
get class Program
{ {
return this.robot.CurrentSpeedInMilesPerHour * 1.6093f; static void Main(string[] args)
{
}
CoolCorpInterface robot = new CoolCorpRobot();
set robot.CurrentSpeedInKilometersPerHour = 3;
{ robot.Jump(12);
this.robot.CurrentSpeedInMilesPerHour = value * 0.62137f; Console.ReadKey();
} }
}
}
public void Jump(float meters) ¿Y si USRobots modifica su interface? Pues nosotros solo tendremos
{ que modificar el adaptador. Mientras que respetemos nuestra
this.robot.Jump(meters * 0.3048f);
interface, no serán necesarios cambios en otras partes del código.
}
}
¿Y si USRobots saca a la venta un nuevo robot, pero hay que
mantener en uso las versiones antiguas? En este caso lo que
tendremos que hacer es crear un nuevo adaptador, que respete
nuestra CoolCorpInterface. Así los clientes no se verán afectados.
Y más si en lugar de utilizar new inyectamos la dependencia con el
adaptador adecuado.
Otras cosas a tener en cuenta
• El patrón Adapter se puede implementar de dos maneras: con
objetos o con clases. Este artículo utiliza la primera opción. Para
implementar el patrón con clases necesitaríamos un lenguaje que
soportase multiherencia. No es el caso de C#.
• Existe otra versión de este patrón denominada Two-Way Adapter. La
idea es similar, pero en este caso, el adaptador implementa las
interface original y la interface adaptada. Algo útil si necesitamos
ambas funcionalidades.
PATRÓN FACADE
• Objetivo: Proporcionar una interfaz unificada a otro conjunto de
interfaces de un subsistema. Façade define una interfaz de más alto
nivel que hace que el subsistema más fácil de usar.
Cuando vimos el patrón Adapter dijimos que el patrón Facade (fachada) estaba muy
relacionado con él. Si bien ambos patrones se basan en el mismo principio (encapsular
la interfaz de otros elementos), es el motivo y el uso que se le va a dar lo que las
diferencia:
• El patrón Adapterconvierte una interfaz en otra, haciendo que la clase cliente pueda
utilizar los métodos de una clase para cuya interfaz no estaba originalmente
preparado.
• El patrón Facade, sin embargo, no realiza ninguna transformación, sino que se limita
a simplificar y centralizar un conjunto de invocaciones en un único punto, a la vez
que desacopla al cliente del subsistema (siendo la clase Facade la que quedaría
acoplada). Es importante tener en cuenta que el patrón Facade no realiza operaciones
de transformación, ya que las clases del subsistema, pese a ser envueltas con este
elemento, pueden seguir siendo accesibles de forma normal en caso de que fuese
necesario, al contrario de lo que ocurre con el patrón Adapter. Un Facade es una
forma de simplificar las cosas: es decisión del diseñador si las clases del subsistema
son accedidas de forma directa o a través de la fachada.
• Resumiendo, Adapter transforma mientras que Facade simplifica y desacopla.
• Cambio manual vs. Cambio automático
• Seguiremos hablando de vehículos para ilustrar nuestros patrones. Un
ejemplo de este patrón aplicado a la vida real sería la diferencia entre
un sistema de cambio manual y un sistema automático. En el primer
caso, el conductor debe interactuar con el embrague, el acelerador y
la palanca de cambios, mientras que en el segundo caso, el conductor
únicamente tiene que preocuparse de acelerar o decelerar, puesto
que será el propio vehículo el que se encargará de realizar todo el
proceso.
• Veamos cómo funcionará el sistema antes de aplicar el patrón Facade:
Tal y como hemos explicado, el conductor debe interactuar con tres elementos del subsistema para realizar un
cambio de marcha. Codificaremos las interfaces del subsistema con las que interactúa el conductor para
comprobar cuál sería su uso normal.
public interface IPalancaCambios public class PalancaCambios : IPalancaCambios
{ {
    private int _velocidadActual;
    void InsertarVelocidad(int velocidad);
    void PuntoMuerto();  
    int GetVelocidadActual();     #region IPalancaCambios Members
}  
    public void InsertarVelocidad(int velocidad)
    {
public interface IEmbrague         Console.WriteLine("Introduciendo marcha " + velocidad);
{         this._velocidadActual = velocidad;
    void PresionarEmbrague();     }
    void SoltarEmbrague();  
}     public void PuntoMuerto()
    {
public interface IAcelerador        Console.WriteLine("Sacando velocidad " + this._velocidadActual);
{        this._velocidadActual = 0;
    void PresionarAcelerador();     }
    void SoltarAcelerador();  
}     public int GetVelocidadActual()
    {
        return _velocidadActual;
    }
 
    #endregion
}
public class Embrague : IEmbrague
public class Acelerador : IAcelerador
{ {
    #region IEmbrague Members     #region IAcelerador Members
   
    public void PresionarEmbrague()     public void PresionarAcelerador()
    {     {
        Console.WriteLine("Embrague presionado");         Console.WriteLine("Acelerador presionado");
    }     }
   
    public void SoltarEmbrague()     public void SoltarAcelerador()
    {     {
        Console.WriteLine("Embrague suelto");         Console.WriteLine("Acelerador levantado");
    }
    }
 
 
    #endregion
    #endregion
}
}

El cliente, por lo tanto, tendría que realizar las siguientes acciones si quisiera realizar un cambio de marcha:

IAcelerador acelerador = new Acelerador();


IEmbrague embrague = new Embrague();
IPalancaCambios palancaCambios = new
PalancaCambios();
 
acelerador.SoltarAcelerador();
embrague.PresionarEmbrague(); Veamos ahora cómo podemos implementar nuestro
palancaCambios.PuntoMuerto();
palancaCambios.InsertarVelocidad(3); patrón Facade para simplificar este proceso y -sobre todo-
embrague.SoltarEmbrague();
acelerador.PresionarAcelerador();
desacoplar al máximo nuestra clase cliente del propio
subsistema.
El principio de mínimo conocimientoTambién conocido como Ley de Deméter, es la base de
la idea de loose coupling o acoplamiento débil. Se basa en los siguientes conceptos:
• Una clase tan sólo debe conocer aquellas otras clases con las que tenga que relacionarse de
una forma estrecha.
• Una clase únicamente debe hablar con sus “amigas”, evitando a toda cosa “hablar con
extraños”.
La razón de ser de esta ley es fomentar uno de los principios básicos de la programación
orientada a objetos: reducir al mínimo el acoplamiento. ¿Que qué es el acoplamiento? El
acoplamiento no es más que el nivel de dependencia que unas clases tienen respecto a
otras. Cuanto menor sea el acoplamiento, menor será el impacto en nuestro programa en el
momento en el que alguno de los elementos del sistema cambie.
Siguiendo con el ejemplo, vemos que el conductor tiene que relacionarse con tres elementos:
el embrague, el acelerador y la palanca de cambios. Imaginemos que nuestro coche tiene una
avería y tienen que cambiarnos la caja de cambios, haciendo que la marcha atrás, en lugar de
estar en la posición inferior derecha, se encuentre en la posición inferior izquierda.
El problema de que cambie este elemento implica que se verán afectados todos los
demás elementos que interactúen con él. En este caso, todos los conductores que utilicen
el vehículo deberán cambiar su comportamiento para adaptarse al nuevo cambio de
interfaz. Cuanto mayor sea el número de conductores, mayor será el número de cambios
que habrá que realizar. La idea del bajo acoplamiento es, precisamente, minimizar las
relaciones entre las clases para que, cuando se dé un cambio (que se dará), las
consecuencias en los elementos adyacentes sean mínimos. Cuanto menos cosas poseas,
menos cosas tendrás que perder. Epicuro habría sido, sin duda, un gran ingeniero de
software.
¿Qué tiene que ver el patrón Facade con todo esto? Pues que si los tres elementos
(acelerador, embrague y palanca de cambios) fuesen accedidos por una interfaz más
sencilla (por ejemplo, una centralita electrónica), el cambio de palanca de cambios no
afectaría a ninguno de los conductores, sino que el cambio en una única clase (la
centralita) haría innecesario hacer cambios en los hábitos de un número indeterminado
de conductores
Así, el patrón Facade realiza, por lo tanto, dos funciones fundamentales:
• Simplificar el uso de las interfaces.
• Desacoplar los clientes del subsistema.
• Creemos, por tanto, nuestra clase Centralita que simplifique la interfaz:
public class Centralita
{
    private IEmbrague _embrague;
    private IAcelerador _acelerador;
    private IPalancaCambios _palancaCambios;
 
    public Centralita(IEmbrague embrague, IAcelerador acelerador, IPalancaCambios palancaCambios)
    {
        this._embrague = embrague;
        this._acelerador = acelerador;
        this._palancaCambios = palancaCambios;
    }
 
    public void AumentarMarcha()
    {
        _acelerador.SoltarAcelerador();
        _embrague.PresionarEmbrague();
        _palancaCambios.PuntoMuerto();
        if (_palancaCambios.GetVelocidadActual() < 5)
            _palancaCambios.InsertarVelocidad(_palancaCambios.GetVelocidadActual() + 1);
        _embrague.SoltarEmbrague();
        _acelerador.PresionarAcelerador();
    }
 
    public void ReducirMarcha()
    {
        _acelerador.SoltarAcelerador();
        _embrague.PresionarEmbrague();
        _palancaCambios.PuntoMuerto();
        if (_palancaCambios.GetVelocidadActual() > 1)
            _palancaCambios.InsertarVelocidad(_palancaCambios.GetVelocidadActual() - 1);
        _embrague.SoltarEmbrague();
        _acelerador.PresionarAcelerador();
    }
}
Si nos fijamos bien en la implementación del patrón, nos daremos cuenta de un par de detalles:
• El patrón contiene una referencia a cada uno de los elementos que encapsula, que son inyectados a través del
constructor (recordemos: la inyección de dependencias es también una buena práctica de programación orientada a
objetos).
• Los parámetros que recibe el constructor son interfaces en lugar de clases. Otro buen principio de programación
orientado a objetos era el de depender de abstracciones, no de concreciones.
• La existencia de la clase Centralita no implica que las clases no puedan utilizarse tal y como las usábamos hasta el
momento: este patrón no reduce la visibilidad de los objetos que encapsula, simplemente ofrece una alternativa
simplificada de su uso.
• Al encapsular las clases dentro de Centralita estamos desacoplando las clases contenidas en ella del resto de clases
cliente, centralizando los cambios en el supuesto de que alguna de las clases acopladas cambie. ¡Ojo! Si decidimos
seguir utilizando las clases encapsuladas por otros medios, no estaremos reduciendo el acoplamiento.
• Finalmente, realizamos la invocación a través de nuestro patrón Facade. El cliente debería implementar un código
muchísimo más sencillo:

IAcelerador acelerador = new Acelerador();


IEmbrague embrague = new Embrague();
IPalancaCambios palancaCambios = new PalancaCambios();
 
Centralita centralita = new Centralita(embrague, acelerador, palancaCambios);
centralita.AumentarMarcha();
• ¿Cuándo utilizar este patrón? Ejemplos reales
Los escenarios más habituales para el uso de este patrón son subsistemas
fuertemente acoplados en los que existan secuencias de interacciones que se
repitan con frecuencia. Un ejemplo real podría darse en el cálculo del riesgo
financiero de un cliente de un banco a la hora de concederle una hipoteca o
un crédito. Un patrón Facade se encargaría aquí de conectar con todos los
subsistemas implicados (créditos, ahorros, impagos) y realizar un cálculo que
proporcione este tipo de información.
Patrón Fachada, otro punto de vista
¿Qué es una fachada o facade en inglés?. Es un patrón de diseño que
nos permite simplificar el interface de comunicación entre dos objetos
A y B de tal forma que para el objeto A sea más sencillo interactuar con
el objeto B. Supongamos que tenemos las siguientes clases:

Vamos a ver el código de Impresora (Java):


package com.genbetadev;
Se trata de una clase sencilla que imprime documentos en uno u
public class Impresora otro formato. El código de la clase cliente nos ayudará a entender
{
private String tipoDocumento;
mejor su funcionamiento.
private String hoja;
private boolean color; package com.genbetadev;
private String texto; public class PrincipalCliente
public String getTipoDocumento() { {
return tipoDocumento; } public static void main(String[] args) {
Impresora i = new Impresora(); i.setHoja("a4");
public void setTipoDocumento(String tipoDocumento) { i.setColor(true); i.setTipoDocumento("pdf");
this.tipoDocumento = tipoDocumento; } i.setTexto("texto 1"); i.imprimirDocumento();

public String getHoja() { Impresora i2 = new Impresora();


return hoja; } i2.setHoja("a4"); i2.setColor(true);
i2.setTipoDocumento("pdf");
public void setHoja(String hoja) { i2.setTexto("texto 2");
this.hoja = hoja; } i2.imprimirDocumento();

public boolean isColor() { Impresora i3 = new Impresora();


return color; } i3.setHoja("a3");
i3.setColor(false);
public void setColor(boolean color) { i3.setTipoDocumento("excel");
this.color = color; } i3.setTexto("texto 3");
i3.imprimirDocumento();
public String getTexto() { }
return texto; } }

public void setTexto(String texto) {


this.texto = texto; }

public void imprimirDocumento() {


System.out.println("imprimiendo:"+ texto+ ",color:" +
color+",tipo:"+tipoDocumento+",hoja :"+hoja); } }
Como podemos ver la clase cliente se encarga de invocar a la
impresora, y configurarla para después imprimir varios documentos
.Ahora bien prácticamente todos los documentos que escribimos
tienen la misma estructura (formato A4, Color , PDF). Estamos
continuamente repitiendo código. Vamos a construir una nueva clase
FachadaImpresoraNormal que simplifique la impresión de documentos
que sean los más habituales.
package com.genbetadev;
De esta forma el cliente quedará mucho más sencillo :
public class FachadaImpresoraNormal
{
Impresora impresora;
public FachadaImpresoraNormal(String texto) {
super();
impresora= new Impresora(); package com.genbetadev;
impresora.setColor(true);
public class PrincipalCliente2
impresora.setHoja("A4"); {
public static void main(String[] args) {
impresora.setTipoDocumento("PDF");
FachadaImpresoraNormal fachada1= new FachadaImpresoraNormal("texto1");
impresora.setTexto(texto); } fachada1.imprimir();
FachadaImpresoraNormal fachada2= new FachadaImpresoraNormal("texto2");
fachada2.imprimir(); Impresora i3 = new Impresora();
public void imprimir() { i3.setHoja("a4");
i3.setColor(true);
impresora.imprimirDocumento(); i3.setTipoDocumento("excel");
i3.setTexto("texto 3");
}
i3.imprimirDocumento();
} }
}
PATRÓN DECORATOR
Objetivo:Añadir responsabilidades a un objeto de forma dinámica. Los
decoradores proporcionan una alternativa flexible a la herencia para
extender funcionalidad.
El siguiente de los patrones estructurales que veremos sera el patrón Decorator o decorador. Su filosofía consiste en
añadir responsabilidades de forma dinámica con el principal objetivo de evitar la conocida como “explosión de clases”,
es decir, la generación de un número elevado de subclases a partir de una superclase común.

Como podemos observar en el gráfico superior, la clase Decorator hereda de la misma clase que el componente que se
quiere decorar. Así, cada decorador es capaz de encapsular una instancia de cualquier otro objeto que herede del
componente común, bien un componente concreto u otro decorador. Este comportamiento recuerda al que vimos
previamente en el patrón Adapter, con la diferencia de que la clase Decorator, a diferencia de la clase Adapter, no
transforma una interfaz, sino que añade cierta funcionalidad.

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 Decoratorsustituye la herencia por un proceso iterativo de composición.
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.
Para comenzar, por tanto, debemos tener claros los siguientes conceptos
sobre este patrón:
• Un decorador hereda de la misma clase que los objetos que tendrá que
decorar.
• Es posible utilizar más de un decorador para encapsular un mismo objeto.
• El objeto decorador añade su propia funcionalidad, bien antes, bien
después, de delegar el resto del trabajo en el objeto que está decorando.
• Los objetos pueden decorarse en cualquier momento, por lo que es posible
decorar objetos de forma dinámica en tiempo de ejecución.
La razón por la que la clase Decorator hereda de la misma clase que el objeto
que tendrá que decorar no es la de añadir funcionalidad, sino la de
asegurarse de que ambos comparten el mismo tipo y puedan
intercambiarse: un decorador podrá sustituir a un objeto decorado,
basándonos en el principio SOLID del Principio de sustitución de Liskov.
Declarando las clases funcionales
Como viene siendo habitual, ilustraremos nuestro patrón haciendo uso de
vehículos. En este caso, utilizaremos una case abstracta, llamada Vehiculo,
del que heredarán las clases funcionales a las que llamaremos “Berlina” y
“Monovolumen”, y los decoradores, que se limitarán a añadir
funcionalidad a estas clases funcionales. Los decoradores que diseñaremos
serán “Diesel”, “Gasolina”, “Inyeccion”, “CommonRail” y “Turbo”.
Estos decoradores se caracterizarán por:
• Disponer de una referencia a un vehículo que será inyectada en el
constructor.
• Modificar el funcionamiento original de la clase que decoran,
sobrecargando los métodos y llamando a los métodos de las clases
encapsuladas para modificar su información o funcionamiento.
• Comencemos codificando nuestra clase abstracta Vehiculo de la cual heredarán
el resto de clases.
public abstract class Vehiculo
{
    // Atributo común a todos los objetos que heredarán de esta clase
    protected string descripcion = "Vehículo genérico";
 
    // Método no abstracto que devolverá el contenido de la descripción
    // Se declara como virtual para que pueda sustituirse en las clases derivadas
    public virtual string Descripcion()
Hecho esto, añadiremos nuestras clases funcionales: Monovolumen y Berlina.
    {
        return descripcion;
    } public class Monovolumen : Vehiculo public class Berlina : Vehiculo
{ {
 
    // Métodos abstractos     public Monovolumen()     public Berlina()
    {     {
    public abstract int VelocidadMaxima();
        descripcion = "Monovolumen";         descripcion = "Berlina";
    public abstract double Consumo();     }     }
}    
    // Funcionalidad básica     public override int VelocidadMaxima()
    public override int VelocidadMaxima()     {
    {         return 180;
        return 160;     }
    }  
      public override double Consumo()
    // Funcionalidad básica     {
    public override double Consumo()         return 6.2;
    {     }
        return 7.5; }
    }
}
• Como vemos, ambas clases heredan un atributo común,
“descripcion”, y la funcionalidad VelocidadMaxima y Consumo.
Asumiremos que un monovolumen posee una velocidad máxima de
160km/h y un consumo de 7,5 litros/100km, mientras que una berlina
podrá alcanzar los 180km/h con un consumo de 6,2 litros/100km. Esta
funcionalidad será modificada por nuestras clases decoradoras, que
podrán aumentar o disminuir estas características.
• Con esto habríamos codificado nuestra rama “funcional”. Aún no hay
rastro del patrón Decorator, ya que únicamente hemos hecho uso de
la herencia de la manera habitual (de hecho, de una forma un tanto
escueta).
Creando las clases decoradoras
Es hora, por tanto, de añadir una nueva “rama” a nuestro árbol, añadiendo
los decoradores. Comenzaremos por crear una nueva clase abstracta que
herede de Vehículo (para que pueda ocupar su lugar) y de la cual heredarán
todos los decoradores.

public abstract class Decorator : Vehiculo


{
    // Declaramos el método como abstracto para que todos los decoradores lo
    // reimplementen.
    public override abstract string Descripcion();
}

A continuación añadiremos los decoradores, que incluirán una referencia a un vehículo y que se construirán mediante la
inyección de éste. Por tanto, las características de estos decoradores, además de heredar de Decorator, serán las
siguientes:

•Contienen una referencia a un Vehículo, que se insertará en el constructor.


•Modifican el funcionamiento de las clases que encapsulan, accediendo a sus atributos y métodos y adaptándolos a la
nueva funcionalidad deseada.
Comenzaremos añadiendo un decorador llamado “Gasolina”. La gasolina, al ser más explosiva,
proporciona mayor velocidad punta, pero al ser menos energética que el gasoil, también conlleva
tener un consumo más elevado. Esta clase tendrá, por tanto, el siguiente aspecto:
public class Diesel : Decorator
public class Gasolina : Decorator
{
{
    // Instancia de la clase vehiculo
    // Instancia de la clase vehiculo
    private Vehiculo vehiculo;
    private Vehiculo vehiculo;
 
      // Constructor que recibe el vehículo que encapsulará el decorator
    // Constructor que recibe el vehículo que encapsulará el decorator
    public Diesel(Vehiculo vehiculo)
    public Gasolina(Vehiculo vehiculo) {
    {
this.vehiculo = vehiculo;
        this.vehiculo = vehiculo;
    }
    }
    // Los métodos utilizan la información del objeto encapsulado y le  
    // incorporan su propia funcionalidad.
    // Los métodos utilizan la información del objeto encapsulado y le
    public override string Descripcion() {     // incorporan su propia funcionalidad.
        return vehiculo.Descripcion() + " Gasolina";     public override string Descripcion()
    }     {
    // Un vehículo gasolina proporciona más potencia, por lo que "decora" el         return vehiculo.Descripcion() + " Diesel";
    // vehiculo añadiendo mayor velocidad máxima     }
    public override int VelocidadMaxima()  {  
        return vehiculo.VelocidadMaxima() + 60;     public override int VelocidadMaxima()
    }     {
    // La gasolina es menos energética que el diesel, por lo que el consumo         return vehiculo.VelocidadMaxima() + 20;
    // de combustible es mayor. Decoraremos el vehículo añadiéndole un consumo     }
    // de 1.2 litros adicionales a los 100 km.
 
    public override double Consumo() {
    public override double Consumo()
        return vehiculo.Consumo() + 1.2;     {
    }
        return vehiculo.Consumo() - 0.8;
}
    }
}
¡Ojo! Según nuestro diseño, un vehículo podría ser a la vez diésel y gasolina, ya que ambos heredan de la
clase Vehículo. Las reglas de negocio no deberían permitir que esto fuera así, por lo que deberíamos utilizar
reglas adicionales para evitar que ambos decoradores estuviesen presentes en un mismo objeto. No obstante,
ignoraremos este hecho en este ejemplo. A continuación añadiremos nuevos decoradores a nuestro vehículo.
Por ejemplo, el turbo.
public class Turbo : Decorator
{
Otra posible modificación al vehículo original podría ser
    private Vehiculo vehiculo; la inyección de combustible, que no afectará a la
 
    public Turbo(Vehiculo vehiculo)
velocidad pero mejorará notablemente el consumo de
    { combustible:
        this.vehiculo = vehiculo; public class Inyeccion : Decorator
    } {
      private Vehiculo vehiculo;
    public override string Descripcion()  
    {     public Inyeccion(Vehiculo vehiculo)
    {
        return vehiculo.Descripcion() + " Turbo";
        this.vehiculo = vehiculo;
    }
    }
   
    public override int VelocidadMaxima()     public override string Descripcion()
    {     {
        return vehiculo.VelocidadMaxima() + 30;         return vehiculo.Descripcion() + " Inyección";
    }     }
   
    public override int VelocidadMaxima()
    public override double Consumo()
    {
    {
        return vehiculo.VelocidadMaxima();
        return vehiculo.Consumo() + 0.4;     }
    }  
}     public override double Consumo()
    {
        return vehiculo.Consumo() - 1.2;
    }
}
• Finalmente, incluiremos un decorador que implemente la tecnología
CommonRail, que disminuirá la velocidad punta pero a cambio
mejorará ligeramente el consumo.
public class CommonRail : Decorator
{
    private Vehiculo vehiculo;
 
    public CommonRail(Vehiculo vehiculo)
    {
        this.vehiculo = vehiculo;
    }
 
    public override string Descripcion()
    {
        return vehiculo.Descripcion() + " Common Rail";
    }
 
    public override int VelocidadMaxima()
    {
        return vehiculo.VelocidadMaxima() - 15;
    }
 
    public override double Consumo()
    {
        return vehiculo.Consumo() - 0.4;
    }
}
Utilizando el patrón Decorator
Es hora de hacer uso del patrón que acabamos de explicar.
Comenzaremos creando un vehículo monovolumen y otro vehículo de
tipo berlina, mostrando por pantalla sus características:
class Program
{
Como vemos, se nos ofrece una versión “básica” de nuestros
    static void Main(string[] args) objetos, que aún no han sido decorados. Probemos a decorar
    {
nuestro monovolumen añadiéndole un motor gasolina:
        Vehiculo monovolumen = new Monovolumen();
        Vehiculo berlina = new Berlina();
 
        MostrarCaracteristicas(monovolumen);
        MostrarCaracteristicas(berlina);
    }
 
    private static void MostrarCaracteristicas(Vehiculo v)
    {
        Console.WriteLine(string.Format("{0}\n\t- Velocidad punta de {1} km/h \n\tConsumo medio de {2} l/100km\n",
                                        v.Descripcion(),
                                        v.VelocidadMaxima(),
                                        v.Consumo()));
    }
}
Vehiculo monovolumen = new Monovolumen();
Se ha modificado, por tanto, su descripción, velocidad punta y
 
// Decoramos el monovolumen añadiéndole un motor gasolina a través consumo medio. Hagamos lo propio con el vehículo de tipo
// del decorador "Gasolina"
Berlina, al que convertiremos en un vehículo diesel turbo
monovolumen = new Gasolina(monovolumen);
  inyección common-rail:
Vehiculo berlina = new Berlina();
Vehiculo berlina = new Berlina();
 
MostrarCaracteristicas(monovolumen);  
MostrarCaracteristicas(berlina); berlina = new Diesel(berlina);
MostrarCaracteristicas(berlina);
 
berlina = new Turbo(berlina);
MostrarCaracteristicas(berlina);
 
berlina = new Inyeccion(berlina);
MostrarCaracteristicas(berlina);
 
berlina = new CommonRail(berlina);
MostrarCaracteristicas(berlina);

Como podemos observar, la propia instancia de


Vehiculo es pasada como parámetro al
constructor, que devuelve la misma instancia
decorada con la nueva funcionalidad. Así, con una única referencia, hemos conseguido modificar el
comportamiento de la instancia en tiempo de ejecución
sustituyendo la capacidad de especialización de la herencia por
un proceso horizontal de composición.
• ¿Cuándo utilizar este patrón? Ejemplos reales
Un ejemplo claro de este patrón en la API de .NET es la familia de clases Stream. La clase Stream es una clase
abstracta que expone la funcionalidad básica que será implementada por las clases concretas y decoradas por
las clases que componen el patrón. Algunas de las clases concretas que podemos encontrar en esta familia son
las siguientes:
• FileStream: representa un flujo (stream) que se encargará de realizar operaciones E/S sobre un fichero físico.
• MemoryStream: representa un flujo que realizará operaciones E/S en memoria. Se usa como una proyección
temporal en memoria de otro flujo.
• BufferedStream: representa una sección de un flujo que realizará operaciones E/S en memoria. La diferencia
con el anterior es que el MemoryStream representa un flujo completo (por ejemplo, una proyección en
memoria de un FileStream), mientras que BufferedStream se usa en conjunción con otros Streams para
realizar operaciones de E/S que posteriormente serán leídas o volcadas desde/hacia el flujo original.
Estas clases serían nuestra Berlina y Monovolumen. Pero ¿y los Decorator? Las clases que actúan como
decoradores son fácilmente identificables porque reciben un Stream como parámetro a la hora de crear una
nueva instancia, a la vez que extienden la funcionalidad del objeto de la clase original.
Algunos de los decoradores que podemos encontrar, y que son aplicables a cualquiera de las tres clases
anteriores son:
• CryptoStream: define una secuencia que vincula los flujos de datos a las transformaciones criptográficas.
• AuthenticatedStream: proporciona métodos para pasar las credenciales a través de una secuencia y solicitar o
realizar la autenticación para las aplicaciones de cliente-servidor.
• GZipStream: proporciona los métodos y propiedades que permiten comprimir y descomprimir secuencias.
Cada uno de estos Decorator reciben en
su constructor un Stream, añadiéndole
nuevas funcionalidades y permitiendo
que sigan actuando como Stream. Debido
al polimorfismo, un CryptoStream que
decore un MemoryStream seguirá
pudiendo sustituir a cualquier objeto que
se pase como parámetro como una
referencia a Stream.

Podemos ver un ejemplo similar en Java, donde la


clase InputStream actuaría como la clase base
abstracta, clases como FileInputStream,
StringBufferInputStream y ByteArrayInputStream
actuarían como clases concretas, FilterInputStream
actuaría como la clase abstracta de la que heredan
todos los decoradores (clase que no existe en la
familia Stream de .NET) y clases como
BufferedInputStream, DataInputStream o
LineNumberInputStream actuarían como
decoradores, recibiendo un objeto de la clase
InputStream como parámetro en su constructor.
Decorator – Nuestra tienda de ordenadores
La utilidad principal del patrón Decorator, es la de dotar de
funcionalidades dinámicamente a objetos mediante composición. Es
decir, vamos a decorar los objetos para darles más funcionalidad de la
que tienen en un principio.
Esto es algo verdaderamente útil cuándo queremos evitar jerarquías de
clases complejas. La herencia es una herramienta poderosa, pero
puede hacer que nuestro diseño sea mucho menos extensible.
Describiendo el problema
Nuestra compañía se dedica a fabricar ordenadores para venderlos. Nosotros somos los desarrolladores encargados
de implementar la lógica del negocio en nuestro lenguaje favorito (en este caso C#). Los ordenadores, de cara al
cliente, tienen una configuración determinada. Por ejemplo, existe el Dummy User PC, que tiene un procesador
normalito, una memoria RAM limitada y un disco duro corriente. También existe el VeryHard Gammer PC que es
mucho más potente. Procesador de última generación, dos tarjetas gráficas con un gritón de RAM, disco duro SSD.
Vamos lo último y más caro.
• Nuestra aplicación debe calcular el precio final del ordenador basándose en sus componentes y un margen de
beneficio en euros que tendrá cada configuración. Los componentes como vemos, no siempre serán los mismos, ya
que dependen de la configuración. Además la configuración puede incluir también periféricos como monitores o
impresoras.
• Para solucionar el problema, y como somos buenos programadores, utilizamos la programación orientada a
objetos.
public Primero
abstract creamos
class una clase abstracta:Esta clase la utilizamos para que las clases que la hereden, se vean
Computer
{
public abstract decimal CalculateCost(); obligadas a implementar su propio método CalculateCost. Usando
} esa clase, tendríamos la siguiente implementación del Dummy PC. La
implementación del VeryHard Gammer PC sería muy parecida.
public class DummyComputer:Computer
{
private decimal processor = 56.00M;
private decimal hdd = 30.00M;
private decimal graphics = 41.99M;
private decimal ram = 23.50M;
public override decimal CalculateCost() {
var cost = this.processor + this.hdd + this.graphics + this.ram; return cost; }
}
Como veis la implementación es muy sencilla. Lo lógico sería buscar en base de datos, o realizar
cálculos más complejos, pero como no es el objetivo del artículo lo hemos simplificado mucho.
Resulta que debido a su servicio de atención al cliente y a sus excelentes precios, la empresa
empieza a crecer. Para aumentar el volumen de negocio se deciden permitir que los clientes
puedan elegir su propia configuración. Desde la tienda online de la empresa, los usuarios podrán
añadir su procesador favorito, un disco duro muy rápido o cantidades enormes de RAM. Y el precio
debe calcularse para que el cliente pueda comprobarlo antes de realizar la compra.
Solución con el patrón Decorator
Al final, decidimos implementar una solución utilizando el patrón Decorator. En este caso, nuestra
clase Computer no sufrirá cambios. Es la que queremos extender así que no la vamos a tocar. Pero si
vamos a crear una nueva clase, que hereda de ella, a la que llamaremos ComponentDecorator.

public abstract class ComponentDecorator:Computer Lo importante de esta clase, es que hereda de la clase original
{ por lo que los objetos se podrán convertir a Computer con un
public override abstract decimal CalculateCost(); simple cast.
} Vale, ¿y cómo añadimos funcionalidad? En este caso hemos
optado por crear una clase por cada componente hardware. A
su vez, cada una de estas clases hereda de
ComponentDecorator. Por ejemplo para un disco duro SSD,
tendremos el siguiente código:
public class FastSSD:ComponentDecorator {
private Computer currentComputer;
public FastSSD(Computer computer)
{
this.currentComputer = computer;
}
public override decimal CalculateCost()
{
return this.currentComputer.CalculateCost() + 255.20M;
} Se puede ver que lo que estamos cogiendo un objeto
} Mientras que para el procesador tope de gama, tendremos el
Computer y lo estamos extendiendo para que el método
siguiente código:
CalculateCost incremente en 120.00 lo que devuelve el
método original. Para poder usar el método original,
public class BigProcessor:ComponentDecorator {
pasamos el objeto Computer como parámetro del
private Computer currentComputer;
constructor.
public BigProcessor(Computer computer) {
Para que todo funcione necesitamos crear una clase base
this.currentComputer = computer; }
desde la que partir, que sería la siguiente:
public override decimal CalculateCost() {
return this.currentComputer.CalculateCost() + 120.00M;
}
}
public class BaseComputer:Computer En este caso el equipo base tiene un coste de 0, pero podría tener cualquier otro
valor. También podemos crear otras configuraciones base, por ejemplo, para
{
portátiles, barebones, netbooks, etc. Las configuraciones base las iremos
public override decimal CalculateCost() { decorando con los distintos componentes, para calcular el precio total.
Y para acabar veamos como usaríamos el patrón, en este caso creando un
return 0M; } Gammer PC
}

Computer gammerPC = new BaseComputer(); gammerPC = new LotOfRAM(gammerPC);


gammerPC = new FastSSD(gammerPC);
gammerPC = new BigProcessor(gammerPC);
var cost = gammerPC.CalculateCost();

Console.WriteLine(string.Format("El Coste del Gammer PC es de {0} euros",


cost));

Ya veis que es muy sencillo. Nos aprovechamos de que nuestros objetos ComponentDecorator, es decir LotOfRAM, FastSSD o
BigProcessor, devuelven objetos Computer. Estos objetos los vamos pasando en el constructor de cada componente. Cuando hemos
acabado de decorar la clase, hacemos una llamada al método para calcular el coste. Esta llamada irá llamando a los métodos CalculateCost
de todos los objetos creados para al final calcular el precio final.
Aunque podríamos haber conseguido algo similar con una jerarquía de clases, probablemente no tendríamos la flexibilidad y dinamismo
que nos proporciona esta solución. Y todo de una manera muy sencilla.
PATRONES ESTRUCTURALES (IV):
PATRÓN BRIDGE
Objetivo:
Desacoplar una abstracción de su implementación de modo que los dos puedan ser modificados de
forma independiente.
El patrón Bridge o Puente es normalmente uno de los patrones que más cuesta
entender, especialmente si nos ceñimos únicamente a su descripción. La idea
tras este patrón, sin embargo, es sencilla: dado que cualquier cambio que se
realice sobre una abstracción afectará a todas las clases que la implementan,
Bridge propone añadir un nuevo nivel de abstracción entre ambos elementos
que permitan que puedan desarrollarse cada uno por su lado.
Si le echamos un ojo al diagrama, es posible que de base no nos aclare
demasiado. Nos centraremos en el elemento central: una clase abstracta
Abstracción que contiene una referencia a una interfaz Implementor y un
método operacion() que no hace más que invocar el método operacionOriginal()
de dicha interfaz. Lo que hace esta clase Abstracción es, por tanto, encapsular a
la interfaz Implementor exponiendo sus métodos.
Similitudes
Un momento… ¿no hemos visto ya esto antes? Nos suena, ¿verdad? ¿No es precisamente lo que realizaba también
el patrón Adapter, tal y como vimos anteriormente?
No vamos por mal camino. La estructura de este patrón se parece mucho a la del patrón Adapter, ya que nuestra
clase Abstracción hace las veces de “adaptador” entre nuestra clase cliente y la interfaz Implementor. Sin embargo,
nos movemos por la sinuosa senda de la ingeniería, por lo que afirmar que Adapter y Bridge realizan lo mismo
simplemente porque su estructura sea muy parecida es quedarnos en la superficie del problema que tratamos de
resolver.
Como recordaremos, el patrón Adapter basaba su razón de ser en la necesidad de adaptar (valga la redundancia) la
interfaz de una clase en otra, para lo cual encapsulaba dicha clase implementando la interfaz que el cliente
requería. Hasta aquí, todo muy parecido, salvando el hecho de que nuestra clase Abstracción no implementa
ninguna interfaz. ¿Por qué? Porque el objeto de este patrón no es realizar una adaptación. La clase cliente no
espera utilizar la interfaz Implementor, sino que sabe que va a hacer uso de una clase derivada de la clase
Abstracción. La razón de ser de esta estructura no es realizar una adaptación, sino separar una interfaz de su
implementación. La diferencia básica entre ambos patrones es, por tanto, que Adapter se utiliza para unificar
interfaces que ya existen, mientras que Bridge se utiliza cuando se sospecha que la implementación de una interfaz
va a cambiar con el tiempo. Adapter intenta cerrar viejas heridas, mientras que Bridge intenta que los errores que
cometieron los miembros que forman parte de Adapter no se vuelvan a repetir. Hay que aprender de la historia,
amigos.
Otro detalle que quizás no quede claro al ver el diagrama UML es que Abstracción es una clase abstracta, por lo que
el objeto que nuestra clase cliente utilizará será una instancia de RefinamientoAbstraccion o de cualquiera de sus
posibles clases hermanas, que serán las que contendrán los métodos refinados. De este modo, las clases que
implementan Implementor podrán evolucionar por un lado mientras las clases heredadas de Abstracción podrán
hacerlo por otro.
¿Por qué “Bridge”?
Patrón tras patrón, vemos que los mismos conceptos se repiten una y otra vez. Minimizar el acoplamiento, hacer que las
clases dependan de abstracciones en lugar de depender de implementaciones, preferir el uso de composición antes que
el uso de herencia… El patrón Bridge no es una excepción. Sin embargo, hasta el momento todos los patrones que hemos
visto tenían una relación entre su nombre y su funcionalidad. Un Adapter adapta. Una factoría fabrica objetos. Un Builder
construye. Pero… ¿Bridge? ¿Qué tiene que ver un puente con todo esto?
Una de las razones por las que opino que este patrón es complicado de entender a la primera es, precisamente, que no
existe una relación clara entre su nombre y su descripción. ¿Llamar puente a desligar una interfaz de la implementación?
¿Por qué? La razón no está tanto en este proceso sino en el camino que existe entre la clase que refina la abstracción y las
implementaciones de la interfaz. Parte de nuestro código estará implementado dentro de nuestra clase
AbstraccionRefinada, y parte estará fuera, por ejemplo en ImplementorConcretoA. Para acceder a ese código, se realiza un
puente de modo que cuando parte del código de nuestra clase AbstraccionRefinada realice una operación cuyo código no
dependa de sí misma, solicite la realización de esta al elemento que se encuentra al otro lado. En el ejemplo de un driver
de un dispositivo, la clase AbstraccionRefinada podría representar operaciones comunes a una plataforma, como por
ejemplo Windows 7. En un momento dado, nuestro driver necesita realizar un acceso a memoria, pero… ¡cuidado! Esta
operación no dependerá únicamente de la plataforma, sino que será dependiente de la arquitectura del sistema.
Bueno, una solución será crear una clase para Windows7 32 bits y otra para Windows 7 64 bits. Así se solucionaría el
problema, ¿verdad? Desde el punto de vista funcional, sí. Pero recordemos que siempre es preferible la composición
antes de la herencia así que… ¿por qué no implementar las operaciones comunes a la plataforma Windows 7 en nuestra
AbstraccionRefinada y dejarle a Implementor y sus implementaciones las tareas dependientes de la arquitectura concreta
que estemos utilizando? De este modo, cuando sea necesario realizar una operación ligada a la arquitectura, bastará con
solicitárselo al ImplementorConcreto que se encuentra al otro lado del puente y que está ligado a una arquitectura
concreta y (más importante) puede ser incorporado a nuestro objeto en tiempo de ejecución.
Hablando en plata, y a modo de resumen, realizaremos la transformación del siguiente árbol de herencia:

En una composición como la siguiente:


Un ejemplo de patrón Bridge
Veamos la aplicación de nuestro patrón Bridge con un ejemplo en
código C#. El ejemplo, como seguro que habréis adivinado, estará
basado en vehículos. Nuestra abstracción simbolizará el vehículo en sí,
mientras que la parte que se tenderá “al otro lado del puente” será el
motor del mismo. Los tipos de vehículo podrán así evolucionar con
independencia de los motores que éstos posean.
Comenzaremos codificando la interfaz Implementor, que en nuestro
ejemplo estará representada por el motor. O más específicamente, por
la interfaz IMotor.
// Implementor
public interface IMotor
{
    void InyectarCombustible(double cantidad);
    void ConsumirCombustible();
}
Como vemos, nada complicado: nuestro Implementor expone dos
métodos, InyectarCombustible y ConsumirCombustible, que deberán
ser codificados en las clases que implementen la interfaz. Y dicho y
hecho, añadiremos un par de clases cuyo papel en el patrón se
corresponderá con ImplementorConcretoA e ImplementorConcretoB, y
modelarán dos tipos de motores: diesel y gasolina.
// ImplementorConcretoA
// ImplementorConcretoB
public class Diesel : IMotor
public class Gasolina : IMotor
{
{
    #region IMotor Members
    #region IMotor Members
   
    public void InyectarCombustible(double cantidad)
    public void InyectarCombustible(double cantidad)
    {
    {
        Console.WriteLine("Inyectando " + cantidad + " ml. de Gasoil");
        Console.WriteLine("Inyectando " + cantidad + " ml. de Gasolina");
    }
    }
   
    public void ConsumirCombustible()
    public void ConsumirCombustible()
    {
    {
        RealizarExplosion();
        RealizarCombustion();
    }
    }
   
    #endregion
    #endregion
   
    private void RealizarExplosion()
    private void RealizarCombustion()
    {
    {
        Console.WriteLine("Realizada la explosión del Gasoil");
        Console.WriteLine("Realizada la combustión de la Gasolina");
    }
    }
}
}
• Con estas tres clases ya habríamos desarrollado el subárbol izquierdo
del diagrama UML que mostramos al comienzo del artículo: la interfaz
Implementor junto a sus implementaciones:
La siguiente parte será encapsular la interfaz
dentro de nuestra abstracción Vehiculo, que
dispondrá de una referencia a IMotor y de un
método que hará uso de los métodos de nuestra
interfaz, encapsulando su funcionalidad tal y
como hacíamos en el patrón Adapter:
// Abstracción
public abstract class Vehiculo
{ Como venimos observando a lo largo de los últimos patrones, el
    private IMotor motor; objeto que implementará el motor es inyectado en el
  constructor, siguiendo el quinto de los principios SOLID:
    public Vehiculo(IMotor motor)
    { principio de inversión de dependencias. De este modo
        this.motor = motor;
    }
desacoplamos aún más la abstracción de la interfaz. Además,
  nuestra clase abstracta dispondrá de otros métodos que no estén
    // Encapsulamos la funcionalidad de la interfaz IMotor
necesariamente relacionados con el puente, como por ejemplo
    public void Acelerar(double combustible)
    { Frenar(). También incorporaremos un método abstracto que
        motor.InyectarCombustible(combustible);
        motor.ConsumirCombustible();
deberá ser implementado por cada una de las clases derivadas.
    } Por último, codificaremos la evolución de nuestra abstracción,
  que se corresponderá con RefinamientoAbstracciónA y
    public void Frenar()
    { RefinamientoAbstracciónB, representadas por dos tipos de
        Console.WriteLine("El vehículo está frenando.");
    }
vehículos: Berlina y Monovolumen.
 
    // Método abstracto
    public abstract void MostrarCaracteristicas();
}
// RefinamientoAbstraccionA
public class Berlina : Vehiculo
{
    // Atributo propio
    private int capacidadMaletero;
 
    // La implementacion de los vehículos se desarrolla de forma independiente
    public Berlina(IMotor motor, int capacidadMaletero) : base(motor)
    {
        this.capacidadMaletero = capacidadMaletero;
    } public class Monovolumen : Vehiculo
{
      // Atributo propio
    // Implementación del método abstracto
    private bool puertaCorrediza;
    public override void MostrarCaracteristicas()
    {  
    // La implementacion de los vehículos se desarrolla de forma independiente
        Console.WriteLine("Vehiculo de tipo Berlina con un maletero con una capacidad de " +
            capacidadMaletero + " litros.");     public Monovolumen(IMotor motor, bool puertaCorrediza)
    }         : base(motor)
}     {
        this.puertaCorrediza = puertaCorrediza;
    }
La clase refinada evoluciona de modo que incorpore sus propios  
    // Implementación del método abstracto
métodos, atributos y constructores. En este caso, un atributo de     public override void MostrarCaracteristicas()
tipo entero que definirá la capacidad en litros del maletero,     {
        Console.WriteLine("Vehiculo de tipo Berlina " + (puertaCorrediza ? "con" : "sin") +
atributo que no dispondrá, por ejemplo, su clase hermana             " puerta corrediza.");
Monovolumen.     }
}

En su lugar, Monovolumen dispondrá de un atributo


puertaCorrediza que indicará si la puerta trasera será corrediz
o no.
Como vemos, cada refinamiento se desarrollará en una dirección, pero ambos elementos podrán
seguir haciendo uso del motor por medio de los métodos codificados en la clase abstracta Vehiculo.
La implementación del método abstracto MostrarCaracteristicas también será diferente. Por lo
tanto, si invocamos este método, toda la funcionalidad contenida en él será parte dependiente de la
propia abstracción (Vehiculo).
Si, por el contrario, necesitáramos hacer uso de funcionalidad no
IMotor motorDiesel = new Diesel(); dependiente del chasis del vehículo, deberíamos “cruzar el puente” y
Vehiculo berlina = new Berlina(motorDiesel, 4);
 
solicitarle la información (o la funcionalidad, en este caso) al motor.
berlina.MostrarCaracteristicas(); O más concretamente, a la implementación del motor, que será
independiente del vehículo.

IMotor motorDiesel = new Diesel(); La invocación de Acelerar invocará, por tanto, los métodos
Vehiculo berlina = new Berlina(motorDiesel, 4); InyectarCombustible y ConsumirCombustible que implementa
 
berlina.MostrarCaracteristicas();
la clase Diesel y expone la interfaz IMotor.
berlina.Acelerar(2.4d);
¿Cuándo utilizar este patrón? Ejemplos reales
Un ejemplo típico de un patrón Bridge lo puede conformar cualquier familia de drivers de
un dispositivo, tal y como vimos en el primer ejemplo.
Otro ejemplo típico suele ser el de las APIs de dibujo. Los elementos genéricos, tales
como formas y figuras serían las abstracciones (por ejemplo, Forma sería el elemento
Abstraction del que derivarían abstracciones refinadas como Circulo o Cuadrado),
mientras que la parte “dependiente” del sistema sería la API concreta que se encargaría
de dibujar en pantalla las formas genéricas definidas en la abstracción. Este
funcionamiento puede observarse en los paquetes de java java.awt y java.awt.peer. (en
Button y List, por ejemplo).
Las situaciones óptimas en los que se debe utilizar este patrón serán, por tanto:
• Cuando se desea evitar un enlace permanente entre la abstracción y (toda o parte de)
su implementación.
• Cuando los cambios en la implementación de una abstracción no debe afectar a las
clases que hace uso de ella.
• Cuando se desea compartir una implementación entre múltiples objetos.
Ejemplo: Patrón Bridge

Para ilustrar todo esto vamos a ver un ejemplo que representará la abstracción del envío de un
paquete. Nuestra interfaz abstracta representará la agencia de transportes que realizará el envío:
public abstract class EmpresaMensajeria{
        protected IEnvio envio;
A continuación vamos a definir la interfaz IEnvio que
representará al implementador del envío:
        protected EmpresaMensajeria(IEnvio envio){
                this.envio = envio;
    }
        public void recogerPaquete(){
                System.out.println('Se ha recogido el paquete.');
                envio.procesarEnvio();
    }
        public void enviarPaquete(){
                envio.enviar();
    }
        public void entregarPaquete(){
                envio.procesarEntrega();
                System.out.println('Se ha entregado el paquete.');
    }
        public void setEnvio(IEnvio envio){
                this.envio=envio;
    }
        public void getEnvio(){
                return this.envio;
    }
}
public interface IEnvio{
public void procesarEnvio();
public void enviar();
public void procesarEntrega();
}

El siguiente paso es crear implementaciones de la interfaz IEnvio:

public class EnvioMar implements IEnvio{


public void procesarEnvio(){
System.out.println('El paquete se ha cargado en el barco.');
}
public void enviar(){
System.out.println('El paquete va navegando por el mar.');
}
public void procesarEntrega(){
System.out.println('El paquete se ha descargado en el puerto.');
}
}

public class EnvioAire implements IEnvio{


public void procesarEnvio(){
System.out.println('El paquete se ha cargado en el avión.');
}
public void enviar(){
System.out.println('El paquete va volando por el aire.'); Ahora crearemos la empresa de transportes refinada:
}
public void procesarEntrega(){
System.out.println('El paquete se ha descargado en el aeropuerto.');
}
}
Y por último hacemos que un cliente utilice nuestra abstracción:
• public class EuroTransport extends EmpresaMensajeria{

        private String nif;


public static void main(String[] args){
        public EuroTransport(String nif){
        // En primer lugar crearemos el objeto que representa a la emrpesa de mensajerio
                IEnvio envioPorDefecto = new EnvioAire();         EmpresaMensajeria mensajero = new EuroTransport("0854752177");

                super(envioPorDefecto);         // Enviaremos un paquete vía aérea, que es la que esta empresa tiene pro defecto
        mensajero.recogerPaquete();
                this.nif=nif;         mensajero.enviarPaquete();
        mensajero.entregarPaquete();
    }
        public EuroTransport(String nif, IEnvio envio){         // Ahora le decimos a la empresa que queremos enviar por mar

                super(envio);         mensajero.setEnvio(new EnvioMar());


        mensajero.recogerPaquete();
                this.nif=nif;         mensajero.enviarPaquete();
        mensajero.entregarPaquete();
    }
        public void identificarse(){ }

                System.out.println("Identificación: "+this.nif);

    }

}
PATRONES ESTRUCTURALES (V):
PATRÓN COMPOSITE
Objetivo:
“Componer objetos en árboles para representar jerarquías todo-parte. Composite permite a los
clientes tratar objetos individuales y objetos compuestos de una manera uniforme”.
El patrón Composite se aleja un poco de la línea tradicional de los patrones vistos hasta ahora, ya
que rompe uno de los principios de la programación orientada a objetos: una clase, una
responsabilidad. En realidad, los más puristas pueden decidir no hacerlo, pero el precio a pagar es
demasiado alto para los ingenieros mortales: la simplicidad del modelo.
Cuando diseñamos debemos tener claro que la idea principal es alcanzar un equilibrio entre
muchos factores como por ejemplo presupuesto, usabilidad y facilidad para que nuestro código sea
reutilizable y pueda ser fácilmente mantenible en un futuro, el sine qua non de este patrón es la
facilidad de uso.
A grandes rasgos, el patrón Composite permite crear una jerarquía de elementos anidados unos
dentro de otros. Cada elemento permitirá alojar una colección de elementos del mismo tipo, hasta
llegar a los elementos “reales” que se corresponderán con los nodos “Hoja” del árbol. Un ejemplo
del concepto de la jerarquía que se pretende modelar sería el de los menús de una aplicación:
En este ejemplo tenemos un menú (Archivo) que contiene varios elementos, que
pueden ser “hojas” que ejecutan una operación (Abrir, CreatePDF en línea.., Compartir
archivos usando SendNow Online…, Adjuntar a correo electrónico…) o bien otro menú
(Guardar como) que a su vez contiene más elementos “hoja” (PDF…, Texto…, Word o
Excel Online…).
Creo que el ejemplo es lo suficientemente ilustrativo como para entender el concepto:
poder anidar menús que puedan contener o bien otros menús, o bien directamente
nodos hoja que ejecuten operaciones. Este ejemplo se aproxima bastante al concepto
de Composite, pero no se ajusta exactamente a su filosofía, ya que le falta una
funcionalidad: el submenú debería ser capaz de ejecutar una operación que se
encargaría de iterar sobre todos los subelementos que contiene, ejecutando la
operación de cada uno de ellos. Sin embargo, deja bastante claro el esquema lógico
que seguirá este patrón.
Llevando el coche al taller
Para ilustrar el patrón, acudiremos a un taller, que tuvo a bien contratar a un ingeniero de software para que
le diseñara una aplicación para realizar el inventariado de las piezas de recambio. El dueño del taller le
expuso al ingeniero la dificultad que tenía para establecer los precios de los recambios, ya que dependiendo
de la avería, a veces era necesario cambiar piezas enteras mientras que en otras ocasiones bastaba con
sustituir un pequeño componente. Nuestro cliente había almacenado en una base de datos cada uno de los
componentes con su respectivo precio, pero cuando el proveedor le aumentaba el precio de una pieza que
formaba parte de otra, tenía que preocuparse de actualizar, una a una, todas las piezas de grano más grueso
en las cuales estaba contenida esta pieza. Por poner un ejemplo, si el precio de un tornillo para una rueda
aumentaba, nuestro mecánico tenía que acceder a su catálogo y modificar el precio total en:
• Tornillo para rueda
• Llantas (en todos y cada uno de los modelos que usaran los tornillos anteriores)
• Ruedas (en todos y cada uno de los modelos que usaran las llantas anteriores)
Como podemos imaginar, esta situación era muy laboriosa. Así pues, nuestro ingeniero desarrolló un
sistema que realizara el cálculo del precio de forma automática a la vez que modelaba el almacén de
recambios con una estructura arborescente. En lugar de disponer del siguiente modelo:
Aplicando Composite
Es hora de ensuciarnos un poco las manos y plantar cara a nuestro código.
Comenzaremos creando nuestro elemento abstracto o interfaz correspondiente
al “Componente”. Esta clase o interfaz debe exponer los métodos comunes tanto
a los elementos compuestos como a los elementos “hoja”. Lo verdaderamente
importante es que este elemento sea una abstracción (depender de
abstracciones, no de concreciones).
• Si optamos por la interfaz, simplemente definiremos sus operaciones.
• Si optamos por la clase abstracta, además de definir sus operaciones,
añadiremos un comportamiento por defecto en el que lanzaremos una
excepción que indique que la operación no está soportada. De este modo, las
clases derivadas deberán encargarse de proporcionar la funcionalidad. En caso
de no proporcionarla, lanzarán una excepción (por ejemplo, el método add en
un elemento Hoja no tiene sentido, por lo que deberá tener este
comportamiento por defecto).
Nuestra clase Componente será, por tanto, el siguiente:
public abstract class ComponenteRecambio
{
    \\Métodos comunes a objetos compuestos y hojas
    public virtual string getNombre() {
        throw new NotSupportedException(this.GetType().Name + "getNombre()");
    }
     public virtual void setNombre(string nombre) {
        throw new NotSupportedException(this.GetType().Name + "setNombre()");
    }
     public virtual string getDescripcion() {
        throw new NotSupportedException(this.GetType().Name + "getDescripcion()");
    }
     public virtual void setDescripcion(string descripcion) {
        throw new NotSupportedException(this.GetType().Name + "setDescripcion()");
    }
     public virtual double getPrecio() {
        throw new NotSupportedException(this.GetType().Name + "getPrecio()");
    }
     public virtual void setPrecio(double precio)  {
        throw new NotSupportedException(this.GetType().Name + "setPrecio()");
    }
 
   \\Métodos exclusivos de los objetos compuestos
     public virtual void add(ComponenteRecambio componente) {
        throw new NotSupportedException(this.GetType().Name + "add()");
    }
 
    public virtual void remove(ComponenteRecambio componente) {
        throw new NotSupportedException(this.GetType().Name + "remove()");
    }
 
    public virtual ComponenteRecambio getElemento(int indice) {
        throw new NotSupportedException(this.GetType().Name + "getElemento()");
    }
}
public class ElementoRecambio : ComponenteRecambio
{
    // Atributos propios del nodo hoja.
Sobre esta clase trabajaremos creando otras dos     private string nombre;
clases que simbolizarán los dos tipos de     private string descripcion;
    private double precio;
elemento que puede contener nuestro patrón  
    // Constructor
Composite: elementos hoja (ElementoRecambio)     public ElementoRecambio(string nombre, string descripcion, double precio)  {
        this.nombre = nombre;
y elementos compuestos (Recambio). Así,         this.descripcion = descripcion;
        this.precio = precio;
nuestros elementos “hoja” serán los que     }
incorporen la verdadera funcionalidad, que será      // Sobrecargamos únicamente los métodos propios de los nodos hoja, destinados
    // a devolver la información y a asignarla
invocada por los elementos compuestos en caso      // NOMBRE
    public override string getNombre() {
de que fuera necesario.         return nombre;
    }
Hemos utilizado “nomenclatura Java” (getters y      public override void setNombre(string nombre) {
        this.nombre = nombre;
setters en lugar de una propiedad para ambas     }
     // DESCRIPCION
operaciones) porque a la hora de sobrecargar los     public override string getDescripcion() {
métodos será más intuitivo si las operaciones se         return descripcion;
    }
encuentran separadas, como veremos más      public override void setDescripcion(string descripcion) {
        this.descripcion = descripcion;
adelante. Por supuesto, para quien lo desee,     }
     // PRECIO
también es posible usar propiedades virtuales y     public override double getPrecio() {
sobrecargarlas del mismo modo que hacemos         return precio;
    }
con estos dos métodos.      public override void setPrecio(double precio) {
        this.precio = precio;
    }
Volviendo a nuestro código, nuestra clase      // Los métodos add, remove y getElemento no se sobrecargarán, ya que
ElementoRecambio almacenará información     // el nodo hoja no estará compuesto por más elementos que él mismo.
    // Por tanto, si se invocan estos métodos, se llamará el método padre
como el nombre, la descripción y el precio:     // que lanzará una excepción de tipo NotSupportedException
}
public class Recambio : ComponenteRecambio
Seguramente, a estas alturas ya nos habremos dado cuenta de lo {
    // Arraylist que contendrá los elementos hijo
que comentábamos al principio del artículo respecto a la ruptura     private ArrayList listaRecambios;
del principio de responsabilidad única. La clase Elemento  
implementa un conjunto de métodos, pero deja otro conjunto sin    // Atributos
    private string nombre;
implementar (los métodos add, remove y getElemento), que     private string descripcion;
lanzarán una excepción si te utilizan. Esos métodos serán  
    // Constructor que recibirá el nombre, el precio y la descripción.
implementados por la siguiente clase: Recambio.     public Recambio(string nombre, string descripcion, double precio) {
        // Instanciamos el ArrayList
        listaRecambios = new ArrayList();
 
        // Asignamos el nombre, la descripción y el precio
        this.nombre = nombre;
        this.descripcion = descripcion;
        this.precio = precio;
     }
 
    //Métodos relacionados con el árbol
     // Añade un nuevo elemento al ArrayList
    public override void add(ComponenteRecambio componente)  {
        listaRecambios.Add(componente);
    }
     // Elimina un elemento del ArrayList
    public override void remove(ComponenteRecambio componente) {
        listaRecambios.Remove(componente);
    }
     // Recupera un elemento del ArrayList
    public override ComponenteRecambio getElemento(int indice) {
        return (ComponenteRecambio)listaRecambios[indice];
    }
 }
En esta primera etapa, hemos codificado la parte que se encarga #region Métodos relacionados con el elemento
 
de añadir, eliminar y consultar otros elementos. El método es
public override string getNombre()
sencillo: a través de un ArrayList interno, los métodos add, {
remove y getElemento realizarán operaciones sobre él.     string nombreCompleto = this.nombre + "\n";
 
A continuación codificaremos los métodos get que recuperarán     foreach(ComponenteRecambio c in listaRecambios)
el contenido de los atributos de cada ElementoRecambio:         nombreCompleto += c.getNombre();
nombre, descripción y precio. Para ello iteraremos sobre los  
    return nombreCompleto;
elementos contenidos dentro de cada Recambio. }
El precio, sin ir más lejos, se calculará a partir de los precios de  
los elementos contenidos en cada ElementoRecambio, que se public override string getDescripcion()
{
sumará al precio del propio componente.     string descripcionCompleta = this.descripcion + "\n";
 
    foreach (ComponenteRecambio c in listaRecambios)
        descripcionCompleta += c.getDescripcion();
 
    return descripcionCompleta;
También sobrecargaremos los métodos setNombre, }

setDescripcion y setPrecio.  
public override double getPrecio()
{
public override void setNombre(string nombre) {     double precioTotal = this.precio;
    this.nombre = nombre;
}
 
public override void setDescripcion(string descripcion) {     foreach (ComponenteRecambio c in listaRecambios)
    this.descripcion = descripcion;         precioTotal += c.getPrecio();
}  
public override void setPrecio(double precio) {     return precioTotal;
    this.precio = precio; }
}  
#endregion
• Recorriendo todos los elementos contenidos dentro de cada recambio
podremos obtener la información almacenada tanto en un objeto
nodo (Recambio) como en un objeto hoja (ElementoRecambio).
Ambos se tratarán de la misma manera, aunque la implementación de
los métodos sea distinta. Y dado que ambos objetos son
intercambiables, estamos consiguiendo lo que declaramos en primera
instancia: componer objetos de forma arborescente respetando la
jerarquía todo-parte permitiendo que ambos elementos se traten de
forma uniforme.
// Declaramos los tornillos incluidos en la llanta, que serán nodos hoja
ComponenteRecambio tornillo1 = new ElementoRecambio("Tornillo llanta", "Tornillo llanta marca ACME", 0.21);
ComponenteRecambio tornillo2 = new ElementoRecambio("Tornillo llanta", "Tornillo llanta marca ACME", 0.21);
ComponenteRecambio tornillo3 = new ElementoRecambio("Tornillo llanta", "Tornillo llanta marca ACME", 0.21);
ComponenteRecambio tornillo4 = new ElementoRecambio("Tornillo llanta", "Tornillo llanta marca ACME", 0.21);
 
// Declaramos la llanta, que poseerá cuatro tornillos. Por tanto, se tratará de un elemento Composite (compuesto
// por otros elementos, que pueden ser compuestos u hojas)
ComponenteRecambio llanta = new Recambio("Llanta ACME 15'", "Llanta ACME de 15'", 42.22);
 
// Añadimos los tornillos a la llanta
llanta.add(tornillo1);
llanta.add(tornillo2);
llanta.add(tornillo3);
llanta.add(tornillo4);
 
// Declaramos ahora otro elemento: la válvula de la rueda
ComponenteRecambio valvula = new ElementoRecambio("Válvula", "Válvula de neumático genérica", 0.49);
 
// Realizamos lo mismo con el neumático
ComponenteRecambio neumatico = new ElementoRecambio("Neumático 15'", "Neumático Michelin de 15'", 13.42);
 
// Declaramos un nuevo objeto compuesto: la rueda.
// Este objeto estará compuesto por la llanta, la válvula y el neumático.
// A su vez, la llanta incluirá los tornillos.
// Establecemos el precio de la rueda a '0', ya que dependerá en exclusiva del contenido de sus elementos.
ComponenteRecambio rueda = new Recambio("Rueda 15'", "Rueda de 15' con llanta ACME y neumático Michelin", 0);
 
// Añadimos a la rueda los elementos hoja que instanciamos previamente
rueda.add(llanta);
rueda.add(neumatico);
rueda.add(valvula);
Purismo vs. Transparencia
Nos acabamos de encontrar con el primer patrón que viola deliberadamente uno de los principios de la
programación orientada a objetos. El motivo ha sido que el incremento en la transparencia (y usabilidad) es tan
importante que merece la pena el sacrificio de permitir que una clase adquiera más de una responsabilidad.
Recordemos que los patrones de diseño son soluciones genéricas a problemas concretos, por lo que su objetivo
es la de facilitar el desarrollo de software. Hay ocasiones, por tanto, en las que las que las ventajas de romper las
normas sobrepasan de largo seguirlas a rajatabla.
¿Cuándo utilizar este patrón? Ejemplos reales
Los escenarios en los que este patrón suele utilizarse son, principalmente:
• Como su propia definición indica, cuando se requiere representar jerarquías todo-parte que superen cierto
tamaño.
• Cuando se desea que los clientes puedan ignorar la diferencia entre colecciones de objetos y objetos
individuales, haciendo que ambos se traten de la misma manera.
• El ejemplo más sencillo de visualizar de este patrón son los controles de un formulario, por ejemplo de
WinForms. Los objetos (botones, literales, paneles…) heredan de la clase Control, que, de base, puede contener
a su vez una colección de otros objetos que hereden de la clase Control. Cada uno de estos controles pueden
tratarse bien como un control individual en sí o como una colección de controles (un panel puede contener, por
poner un ejemplo, un Label, un Button y un RadioButton).
• El sistema del pipeline de petición/respuesta de ASP.NET también sigue este esquema.
• Finalmente, la estructura de ficheros y directorios de un sistema de archivos también actúa en consonancia con
este patrón.
Patrón composite, un ejemplo:
• Vamos a ver un ejemplo para dejar todo más claro. Tenemos que
diseñar un sistema que permita dibujar planos de una zona concreta.
Las zonas pueden ser una ciudad, un barrio, una calle, una avenida, una
plaza o una travesía. En primer lugar definiremos una interfaz que
represente la zona a dibujar, que hará de Component:
• interface Zona {
     public void generarPlano();
     public String obtenerTipo();
     public void agregarZona(Zona z);
     public Zona subzona(int i);
}
El siguiente paso es definir las zonas que pueden estar compuestas por
otras zonas. Por ejemplo, una ciudad tiene varios barrios que a su vez
están compuestos por domicilios. Lo haremos mediante la
implementación de la interfaz zona:
interface Zona { El siguiente paso es definir las zonas que pueden estar
     public void generarPlano(); compuestas por otras zonas. Por ejemplo, una ciudad tiene
     public String obtenerTipo(); varios barrios que a su vez están compuestos por domicilios. Lo
     public void agregarZona(Zona z); haremos mediante la implementación de la interfaz zona:
     public Zona subzona(int i);
}
public class Ciudad implements Zona{ public class Barrio implements Zona {      
     private String nombre; private String nombre;      
    private ArrayList subzonas; private ArrayList subzonas;
     public Ciudad(String nombre){        public Barrio(String nombre){           
          this.nombre = nombre;            this.nombre = nombre;           
subzonas = new ArrayList();       subzonas = new ArrayList();      
}       }
public void generarPlano(){      public void generarPlano() {           
          System.out.println("CIUDAD: "+this.nombre); System.out.println("BARRIO: "+this.nombre);           
          for(int i=0;i<subzonas.size();i++){ for(int i=0;i<subzonas.size();i++){
               subzonas.get(i).generarPlano();                subzonas.get(i).generarPlano();          
          }     }
}             }      
public void obtenerTipo(){ public void obtenerTipo() {           
          return "ciudad";       return "barrio";    
}       }      
public void agregarZona(Zona z){
        // Las ciudades se subdividen en barrios public void agregarZona(Zona z) {           
         if(z.getTipo().equals("barrio")){ // Un barrio no puede tener ni barrios ni ciudades dentro de el.
               subzonas.add(z); } else {                 if(!(z.getTipo().equals("ciudad") || (z.getTipo().equals("barrio")){
System.out.println("No se puede añadir "+z.getTipo()+" directamente a una ciudad.");                subzonas.add(z);           
     }       } else {
     public Zona subzona(int i){                System.out.println("No se puede añadir "+z.getTipo()+" directamente a un barrio.");           
          return subzonas.get(i);       }      
} }      
} public Zona subzona(int i){
          return subzonas.get(i);           
}      
}

Nos queda por implementar el resto de zonas, las que no son composiciones (zonas finales u hojas) o son composiciones sin hijos:
public class Calle implements Zona{ public class Avenida implements Zona{
private String nombre; private String nombre;

public Calle(String nombre){ public Avenida(String nombre){


this.nombre = nombre; this.nombre = nombre;
} }

public void generarPlano(){ public void generarPlano(){


System.out.println("CALLE: "+this.nombre); System.out.println("AVENIDA: "+this.nombre);
} }

public void obtenerTipo(){ public void obtenerTipo(){


return "calle"; return "avenida";
} }

public void agregarZona(Zona z){ public void agregarZona(Zona z){


System.out.println("No se pueden agregar zonas a "+z.getTipo()); System.out.println("No se pueden agregar zonas a "+z.getTipo());
} }

public Zona subzona(int i){ public Zona subzona(int i){


System.out.println("Este elemento no contiene subzonas"); System.out.println("Este elemento no contiene subzonas");
} }
} }
public class Plaza implements Zona{ public class Travesia implements Zona{
private String nombre; private String nombre;

public Plaza(String nombre){ public Travesia(String nombre){


this.nombre = nombre; this.nombre = nombre;
} }

public void generarPlano(){ public void generarPlano(){


System.out.println("PLAZA: "+this.nombre); System.out.println("TRAVESIA: "+this.nombre);
} }

public void obtenerTipo(){ public void obtenerTipo(){


return "plaza"; return "travesia";
} }

public void agregarZona(Zona z){ public void agregarZona(Zona z){


System.out.println("No se pueden agregar zonas a "+z.getTipo()); System.out.println("No se pueden agregar zonas a "+z.getTipo());
} }

public Zona subzona(int i){ public Zona subzona(int i){


System.out.println("Este elemento no contiene subzonas"); System.out.println("Este elemento no contiene subzonas");
} }
} }
public static void main(String[] args){
// Creamos una lista de zonas Bien, ya tenemos todos los tipos de zonas
ArrayList zonas = new ArrayList();
definidos, ahora toca crear un cliente para
Zona madrid = new Ciudad("Madrid");

Zona vallecas = new Barrio("Vallecas");


probar la funcionalidad:
Zona chamberi = new Barrio("Chamberí");
Zona hortaleza = new Barrio("Hortaleza");

vallecas.agregarZona(new Calle("Alameda del Valle"));


vallecas.agregarZona(new Travesia("Gavia"));

chamberi.agregarZona(new Avenida("Reina Victoria"));


chamberi.agregarZona(new Plaza("Colón"));

hortaleza.agregarZona(new Travesia("Biosca"));
hortaleza.agregarZona(new Avenida("América"));

madrid.agregarZona(vallecas);
madrid.agregarZona(chamberi);
madrid.agregarZona(hortaleza);

zonas.add(madrid);
zonas.add(new Ciudad("Barcelona"));
zonas.add(new Barrio("Georgetown"));
zonas.add(new Calle("Aleatoria"));

// Como veis, tenemos zonas de varios tipos y varios niveles Generaremos todos los planos independientemente del nivel
for(int i=0; i<zonas.size();i++){
zonas.get(i).generarPlano();
}
}
PATRONES ESTRUCTURALES (VII):
PATRÓN PROXY
Objetivo:
“Proporcionar un sustituto o intermediario para otro objeto de modo
que pueda controlarse el acceso que se tiene hacia él”.
Supongo que todos conocemos el concepto de proxy, al menos en su
acepción aplicada a la navegación web. Se trata de una máquina que actúa
de intermediaria a la hora de servir páginas web (u otros servicios). En la
configuración de área local podemos indicar la IP de esta máquina y será
esta máquina la que se conecte a la URL por nosotros y la envíe a nuestro
equipo. De este modo, un equipo no se conectará directamente a la
URL, sino que lo hará a través de este intermediario. ¿Por qué
hacer esto? Por múltiples motivos: podemos, por ejemplo,
restringir las URLs que nuestros clientes (ordenadores de la red
local) pueden visitar. O cachear las páginas que se visitan con
más frecuencia, haciendo innecesario el acceso a la web “real”
en los casos en los que el acceso se repita, proporcionando un
ahorro en ancho de banda. En resumen, un proxy será una
entidad en la que delegaremos la ejecución de ciertas tareas y
que decidirá, en última instancia, qué acciones realizar antes y
después de éstas. Los proxies, por tanto, podrían dedicarse
perfectamente a la política
Tipos de proxy
Dependiendo de las responsabilidades y del comportamiento del proxy,
tendremos varios tipos que realizarán unos tipos de tarea u otras. Los proxies
más comunes son los siguientes:
• Proxy remoto: un proxy remoto se comporta como un representante local de
un objeto remoto. Se encarga principalmente de abstraer la comunicación
entre nuestro cliente y el objeto remoto. Es el embajador de los proxies.
• Proxy virtual: se encarga de instanciar objetos cuyo coste computacional es
elevado. Es capaz de sustituir al objeto real durante el tiempo que el
verdadero objeto está siendo construido y proporcionar funcionalidades
como el lazy loading (realizar operaciones computacionalmente costosas
únicamente cuando el acceso a el elemento es requerido).
• Proxy de protección: establece controles de acceso a un objeto dependiendo
de permisos o reglas de autorización.
Estructura del patrón
Si echamos un vistazo al diagrama, vemos que la estructura de este patrón es bastante sencilla:
• Tenemos una clase abstracta (o interfaz) Elemento que define las operaciones que deberá
cumplimentar tanto nuestro objeto real (ElementoReal) como el proxy que actuará de
intermediario (ElementoProxy). Ambos elementos, al heredar de Elemento, deberán ser, por
tanto, intercambiables. De este modo, sustituir un objeto de la clase ElementoReal por un
ElementoProxy debería de ser -idealmente- transparente.
• La clase ElementoReal es aquella que contiene la verdadera funcionalidad, es decir, la clase que
se quiere “proteger” a través del proxy. En el ejemplo de los navegadores, se correspondería al
ordenador que realiza la petición HTTP. Este elemento tendrá un conjunto de operaciones,
heredadadas desde Elemento. Usando el símil de los ordenadores, una operación podría ser
HttpGet o HttpPost.
• La clase ElementoProxy también hereda de Elemento, y como tal, posee todos sus métodos. La
diferencia fundamental es que también incorpora una referencia a otro Elemento. Así, tal y como
ocurría en otros patrones como Adapter o Decorator, el método codificado dentro de esta clase
realizará ciertas operaciones de control y/o transformación para posteriormente invocar el
método original del ElementoReal que tiene referenciado. Por ejemplo, si nuestro proxy no
quisiera permitir las conexiones a una página en concreto, su comportamiento sería algo similar
al siguiente:
private class ElementoProxy : Elemento
{
// Incluímos una referencia a otro elemento.
private Elemento elemento;

// Inyectamos el elemento a través del constructor.


public ElementoProxy(Elemento elemento)
{
this.elemento = elemento;
}

// El método HttpGet realizará comprobaciones y/o adaptaciones para


// posteriormente realizar la llamada al método homónimo del objeto real
public string HttpGet(string uri)
{
if (uri.ToLower().Contains("paginaprohibida.com"))
return null;
else
return HttpGet(uri);
}
};
A estas alturas, si habéis echado un ojo a los patrones anteriores, este concepto os resultará pan comido. El
patrón Proxy realiza una tarea similar a la que realizaba el patrón Adapter, salvo que en lugar de
transformar la interfaz del objeto (ambos objetos heredan de la misma clase y, por tanto, comparten
interfaz), éste utilizará la misma, pero realizando una serie de operaciones adicionales antes (o después) de
realizar la llamada al método de la clase original.
Es más, el concepto de añadir funcionalidad a una clase que puede hacerse pasar por otra añadiendo
nueva funcionalidad inyectando el objeto original a través del constructor es un concepto que también
hemos visto antes en el patrón Decorator.
El patrón Proxy es muy similar a éste último, con la diferencia (nuevamente) de su objetivo: mientras que el
patrón Decorator añade nuevas responsabilidades a un objeto de forma dinámica, el patrón Proxy
únicamente realiza operaciones de control de acceso sobre ese objeto. De hecho, el Proxy tiene una
capacidad que no tiene el Decorator: tiene la capacidad de instanciar objetos de la clase que encapsula. En
el ejemplo aquí mostrado el objeto es inyectado, pero en determinados casos, este podría ser
perfectamente instanciado. Esto suele ser común en el llamado Virtual Proxy, en el que el Proxy puede
proporcionar un comportamiento “por defecto” mientras realiza la operación que requiera cierto coste
computacional.
Por lo tanto, nos encontramos una colección de cosas que ya nos son familiares: una clase abstracta de la
que heredan ambos elementos, inyectar un objeto en otro a través de su constructor, realizar una
composición de objetos al añadir una referencia del objeto original dentro del objeto de la clase proxy…
Como vemos, los mismos conceptos se repiten una y otra vez. Una vez comprendidos, la comprensión de
los patrones se simplifica muchísimo.
Otra posible versión de este patrón resultaría en realizar la herencia de
forma lineal, es decir, haciendo que el proxy herede del elemento real y
sobrecargando los métodos que requieran supervisión.
Con este modelo evitaremos que nuestro proxy tenga que
incluir una referencia al objeto real, ya que podemos
realizar la misma operación sobrecargando el método y
llamando al método de la clase base en lugar de invocar
el método del objeto inyectado a través del constructor.
Usando esta estructura podríamos incluso evitar que
ElementoReal herede de una clase abstracta o
implemente una interfaz, simplificando el código… pero
forzando a nuestro diseño que dependa de una
concreción en lugar de depender de una abstracción. En
la medida de la posible, intentaremos respetar este
principio.
Arrancando el vehículo
Atrás quedaron los días en que el sistema de arranque de nuestro vehículo consistía en una llave
dentada que encajaba con los pernos de la cerradura. La electrónica y la informática hace tiempo
que ha llegado a la automoción, y por ello la nueva serie de vehículos Dorfwagen incorpora una
centralita con un complejo sistema de seguridad que es capaz de comprobar si el código de la llave
coincide con el de la centralita. En los modelos de gama alta, además de realizar esta operación
estándar, la centralita proporciona un sistema de seguridad capaz de detectar si la llave ha sido
falsificada.
Nuestra centralita, por tanto, proporciona dos atributos: uno que se corresponderá con el código de
la llave y otro que identificará al código de seguridad.
public class CentralitaVehiculo
{
    private int codigoLlave; Dado que disponemos de dos gamas (alta y baja), necesitaremos
    private int codigoSeguridad; implementar, partiendo de la misma centralita, un sistema que
 
    public CentralitaVehiculo(int codigoLlave, int codigoSeguridad) sea compatible con ambos pero que sea capaz de realizar una
    {
        this.codigoLlave = codigoLlave; comprobación adicional si la llave del vehículo es de gama alta.
        this.codigoSeguridad = codigoSeguridad;
    }
Comenzaremos codificando la clase abstracta Llave de la cual
  heredará tanto la funcionalidad base de nuestra llave LlaveReal
    public int CodigoLlave {
        get { return codigoLlave; } como la clase que hará de veces de proxy, LlaveProxy.
    }
    public int CodigoSeguridad {
        get { return codigoSeguridad; }
    }
}
// Clase abstracta de la que heredará el elemento original y el proxy
public abstract class Llave Esta llave contiene un atributo que almacenará el código de la llave,
{
    // Código de la llave
más dos métodos que deberán ser implementados por las clases hija:
    protected int codigoLlave; RealizarContacto, que arrancará el vehículo, y LlaveCorrecta, que será
 
    // Propiedad de sólo lectura para obtener el código de la llave
invocada por el método anterior y comprobará si el código de la
    public int CodigoLlave centralita y de la llave coinciden.
    {
        get { return codigoLlave; } Nuestra clase LlaveReal, por tanto, mostrará el comportamiento básico
    } que se espera de ella: comprobará que llave y centralita comparten
 
    // Métodos abstractos que implementarán el elemento real y el proxy código y realizará el arranque del vehículo en caso de que así sea.
    public abstract void RealizarContacto(CentralitaVehiculo centralita);
    public abstract bool LlaveCorrecta(int codigoLlave);
} public class LlaveReal : Llave
{
    // Constructor base: asigna el código de la llave a la llave
    public LlaveReal(int codigoLlave)
    {
        this.codigoLlave = codigoLlave;
    }
 
    // Realizar contacto: comprueba que el código de la llave sea correcto.
    // En caso de que lo sea, arranca el vehículo.
    public override void RealizarContacto(CentralitaVehiculo centralita)
    {
        if (LlaveCorrecta(centralita.CodigoLlave))
            Console.WriteLine("Contacto realizado");
        else
            Console.WriteLine("Código de llave inválido");
    }
 
    // Comprueba que el código proporcionado coincide con el de la llave
    public override bool LlaveCorrecta(int codigoLlave)
    {
        return codigoLlave == this.codigoLlave;
    }
}
Hasta aquí, nada que se separe de un diseño convencional. Es hora de
implementar nuestro proxy, que también hereda de Llave. La diferencia
fundamental con la clase anterior radica en que:
• Su constructor acepta un objeto de la clase Llave, que será inyectado para ser
invocado en los métodos LlaveCorrecta y RealizarContacto.
• Debido a lo anterior, nuestra clase deberá incluir una referencia a Llave.
• El método LlaveCorrecta se limitará a invocar el método LlaveCorrecta de la
llave que se ha inyectado a través del constructor.
• Finalmente, el método RealizarContacto será el encargado de realizar la
comprobación adicional: antes de comparar los códigos de la llave y de la
centralita invocando a LlaveCorrecta realizará una comprobación previa,
utilizando algún tipo de algoritmo para asegurarse de que el código de
seguridad de la centralita permite el código de la llave insertada. En caso de que
sea correcto, el control de acceso habrá sido superado y se ejecutará el código
correspondiente a LlaveReal. En caso contrario, se denegará el arranque:
La llave simple realizará un arranque normal y correcto siempre
public class LlaveProxy : Llave
{ que el código de centralita y de la llave coincidan. No obstante,
    // Referencia a la llave original
en los vehículos de gama alta, si utilizamos un código de
    private Llave llaveOriginal;
  seguridad erróneo, el motor no arrancará:
    // Constructor en el que se inyectará el objeto real
    public LlaveProxy(Llave llave) { int codigoLlave = 532543463;
        llaveOriginal = llave; int codigoSeguridad = 1038948470;
    }  
  CentralitaVehiculo centralita = new CentralitaVehiculo(codigoLlave, codigoSeguridad);
    // Este método realizará el control de acceso sobre el método original.
    // Realizará una comprobación previa comparando el código de seguridad y, si este es
 
    // correcto, invocará el método del objeto real. Llave llaveSimple = new LlaveReal(codigoLlave);
    public override void RealizarContacto(CentralitaVehiculo centralita) { llaveSimple.RealizarContacto(centralita);
        // Realizamos una comprobación adicional de seguridad. En caso de no cumplirse, se  
        // aborta la operación. Esta operación podría ser la ejecución de un algoritmo para Llave proxy = new LlaveProxy(llaveSimple);
        // comprobar la autenticidad del código de la llave, una comprobación de nombre de proxy.RealizarContacto(centralita);
        // usuario y contraseña... o cualquier otra comprobación que queramos realizar.
        if (centralita.CodigoSeguridad > llaveOriginal.CodigoLlave.ToString().GetHashCode())
        {
            Console.WriteLine("Código de seguridad incorrecto. Abortanto arranque"); Por el contrario, si el código es válido, se procederá al arranque
            return;
        }
de forma normal.
        if (LlaveCorrecta(centralita.CodigoLlave)) int codigoLlave = 532543463;
            Console.WriteLine("Contacto realizado");
        else int codigoSeguridad = -1098948470;
            Console.WriteLine("Código de llave inválido");  
    } CentralitaVehiculo centralita = new CentralitaVehiculo(codigoLlave, codigoSeguridad);
   
    // Este método no realizará comprobaciones adicionales. Se limitará a invocar el método
Llave llaveSimple = new LlaveReal(codigoLlave);
    // del objeto real.
llaveSimple.RealizarContacto(centralita);
    public override bool LlaveCorrecta(int codigoLlave) {
 
        return llaveOriginal.LlaveCorrecta(codigoLlave);
Llave proxy = new LlaveProxy(llaveSimple);
    }
proxy.RealizarContacto(centralita);
¿Cuándo utilizar este patrón? Ejemplos reales
Este patrón es aconsejable en los siguientes supuestos:
• Retrasar una invocación a una petición con alto coste computacional hasta que sea necesario (lazy loading). Un
ejemplo de este comportamiento sería, por ejemplo, cumplimentar un diccionario interno que requiera realizar
varias conexiones a base de datos únicamente cuando se solicite información de uno de los elementos
contenidos en el diccionario.
• Simplificar la interacción con elementos remotos: si el objeto es local, las invocaciones serán las habituales. Si el
objeto es remoto, el proxy implementará los mecanismos de comunicación haciéndolos transparentes al cliente.
Ejemplos de este patrón pueden ser la tecnología RMI de Java, en el que la invocación de un objeto remoto se
realiza a través de un Stub. Este Stub no es más que una clase que expone las mismas operaciones que el objeto
remoto, pero que hace que la petición sea transparente para el cliente, realizando de forma interna las
operaciones de comunicación.
Otro ejemplo serían las pantallas de carga de ciertas aplicaciones. En este caso, se tratará de un Proxy Virtual, que
mostrará el típico mensaje de “Cargando” mientras recupera la información solicitada por el usuario,
sobreescribiendo el mensaje una vez que la petición al objeto real ha concluido.
PATRONES DE
COMPORTAMIENTO
PATRONES DE COMPORTAMIENTO (I):
PATRÓN ITERATOR
Objetivo:
“Proporcionar una forma de
acceder a los elementos de un
objeto agregado de forma
secuencial sin exponer sus
detalles”.
Pese a que no seamos conscientes de ello, cuando programamos utilizamos el patrón Iterator a
diario. Casi todas las estructuras de datos que representan colecciones utilizan de algún modo
este patrón para proporcionar acceso secuencial a los elementos que las conforman, y tanto Java
como .NET ofrecen interfaces que nos invitan a implementar este patrón codificando su
comportamiento.
Ojo al detalle: hemos dicho recorrer secuencialmente, esto es, hacer uso de un proceso que sea
capaz de situarse en el primer elemento de una colección y obtener la información de ese
contenido. Tras esto, dado que hemos dicho que se trata de una operación secuencial,
deberemos ser capaces de pasar del elemento actual al elemento al siguiente, obteniendo
también su contenido. Por último, será necesario implementar algún mecanismo que nos
informe si hemos alcanzado el final de la colección para detener el proceso de iteración.
Por lo tanto, el patrón Iterator debe proporcionar la siguiente funcionalidad:
• Obtener una referencia al elemento actual de la colección.
• Obtener una referencia al siguiente elemento de la colección (el situado a continuación del
elemento actual).
• Obtener información sobre si existen más elementos después del actual.
• Reiniciar la colección para que el iterador apunte nuevamente al primer elemento de la
colección.
Seguramente podremos pensar que no tiene mucho sentido implementar nuestro propio patrón Iterator, ya
que prácticamente todas las colecciones implementan todas estas operaciones (e incluso alguna más). Sin
embargo, existirán muchos supuestos en los que nos será útil.
Comencemos por el principio. Imaginemos que disponemos de una fábrica de vehículos. Esta fábrica guarda
un registro pormenorizado de los vehículos que fabrica, que están modelados a través de la siguiente clase:
Como nuestros ingenieros han sido previsores, han decidido que
public class Vehiculo
{
la estructura de datos en la cual se almacenarán los vehículos
    public string Marca { get; set; } implemente una interfaz, a la que llamaremos
    public string Modelo { get; set; } IRegistroVehiculos. Esta interfaz definirá las operaciones
    public DateTime FechaFabricacion { get; set; }
básicas que se harán sobre el registro, que serán insertar un
    public double Precio { get; set; }
  nuevo vehículo y mostrar información sobre éste (un ejemplo
    public Vehiculo(string marca, string modelo, más completo también incluiría métodos para eliminar y
        DateTime fechaFabricacion, double precio) modificar, pero nos centraremos de momento en esta
    {
        this.Marca = marca; funcionalidad básica para no desviarnos del ejemplo):
        this.Modelo = modelo;
        this.FechaFabricacion = fechaFabricacion;
        this.Precio = precio;
    }
public interface IRegistroVehiculos
  {
    public string CaracteristicasVehiculo()
    void InsertarVehiculo(string marca, string modelo, double precio);
    {
    Vehiculo MostrarInformacionVehiculo(int indice);
        return Marca + " " + Modelo + " fabricado en " +
}
            FechaFabricacion.ToShortDateString() + " con un precio de " +
            Precio + " euros.\n";
    }
}
Nuestra fábrica de vehículos posee un sistema de gestión que almacena los
vehículos en una estructura de datos agregada, como por ejemplo un ArrayList.
Nuestra clase, como podremos imaginar, implementará la interfaz
IRegistroVehiculos:
public class RegistroVehiculos : IRegistroVehiculos
{
    private ArrayList listaVehiculos;
 
    public RegistroVehiculos()
    {
        this.listaVehiculos = new ArrayList();
    }
 
    public void InsertarVehiculo(string marca, string modelo, double precio)
    {
        Vehiculo v = new Vehiculo(marca, modelo, DateTime.Now, precio);
        listaVehiculos.Add(v);
    }
 
    public Vehiculo MostrarInformacionVehiculo(int indice)
    {
        return (Vehiculo)listaVehiculos[indice];
    }
}
Iterator entra en escena
Hasta ahora hemos creado una clase que contendrá la información sobre los vehículos y otra que
contendrá un listado de éstos y será capaz de añadir nuevos vehículos y recuperar un vehículo del cual le
pasaremos un índice. Sin embargo, aún no hemos visto ni rastro del patrón Iterator por ningún sitio. Este
patrón es, precisamente, la pieza que nos falta para que nuestro modelo esté completo. Si al método
MostrarInformacionVehiculo le pasamos un índice mayor que el número de elementos que contenga el
ArrayList, lo que obtendremos será una bonita excepción de índice fuera de rango. Una posible solución
sería comprobar dentro del método que el número de elementos menos uno es siempre mayor o igual
que el índice pasado como parámetro, pero esto no arreglaría el problema: necesitamos una estructura
que sea capaz de iterar sobre la colección e informar al cliente si existen más elementos disponibles. Es
hora de implementar un iterador.
Para esta implementación utilizaremos, nuevamente, una interfaz que definirá las operaciones que
tendrá que realizar. Estas operaciones ya las hemos definido al principio del artículo: un método que
“reinicie” el iterador colocándolo en el primer elemento, otro que devuelva el elemento actual, otro que
nos devuelva el siguiente elemento (incrementando el índice en una unidad) y otro que nos informe si
quedan elementos disponibles en public
la colección:
interface IIteratorVehiculo
{
    void Primero();
    Vehiculo Actual();
    Vehiculo Siguiente();
    bool QuedanElementos();
}
• Comencemos a implementar nuestro iterador. Además de heredar de
IIteratorVehiculo, deberá contener una referencia al listado completo de elementos del
ArrayList. El método para realizar esta operación, como habremos podido imaginar, se
realizará inyectándolo a través del constructor. Además, añadiremos una variable
entera que se ocupe de almacenar el índice del elemento en el que se encuentra el
iterador en este momento.
public class IteratorVehiculo : IIteratorVehiculo Hemos inicializado la variable posicionActual al valor -1, lo
{ cual implica que nuestro iterador se encuentra en la posición
// Referencia al listado completo inmediatamente anterior a la primera posición. El método
private ArrayList vehiculos; Primero(), de hecho, debería realizar esta misma operación:

// Almacenaremos el índice en el que se encuentra el iterador


private int posicionActual = -1;

// El constructor inyectará el ArrayList en el objeto // Operación 1: Reinicio del índice, colocándolo en el elemento
public override IteratorVehiculo(ArrayList listado) anterior al primero
{ public void Primero()
this.vehiculos = listado; {
} this.posicionActual = -1;
} }
Espera, espera, ¿Por qué colocarlo antes del primer elemento en lugar de referenciar directamente el primer elemento? ¿No sería más
intuitivo? Sí, pero sería erróneo. Si el método Primero() colocara el cursor en el primer elemento, ¿qué ocurriría si la lista estuviera vacía?
Exacto: estaríamos referenciando un elemento que no existe, y lo que es peor: no tendríamos modo alguno de que nuestro iterador nos
informara si existen elementos, ya que el método QuedanElementos(), encargado de esta operación, no podría actuar sobre el primer
elemento de la colección. Colocando el índice en el elemento inmediatamente anterior solucionaríamos directamente estos dos problemas.
Lo siguiente que haremos será codificar el método Actual(), que nos devolverá una referencia al elemento cuyo índice se corresponda con el
almacenado en posicionActual(), realizando, eso sí, las comprobaciones pertinentes.

// Operación 2: Acceso al elemento actual


public Vehiculo Actual()
{
// Si no existen elementos, devolveremos null.
// Si el indice actual es mayor que el mayor indice aceptable, devolveremos null.
// Si el indice actual es -1, devolveremos null.
if ((this.vehiculos == null) || Como el índice puede ser -1, será también necesario controlar
(this.vehiculos.Count == 0) || esta posibilidad.
(posicionActual > this.vehiculos.Count - 1) || La siguiente operación nos ofrecerá una referencia al elemento
(this.posicionActual < 0)) siguiente, incrementando el índice en una unidad.
return null;

// Devolvemos el elemento correspondiente al elemento actual


else
return (Vehiculo)this.vehiculos[posicionActual];
}
// Operación 3: Acceso al siguiente elemento
public Vehiculo Siguiente()
{
// Si no existen elementos, devolveremos null.
// Si el indice siguiente es mayor que el mayor indice aceptable, devolveremos null.
if ((this.vehiculos == null) ||
(this.vehiculos.Count == 0) ||
(posicionActual + 1 > this.vehiculos.Count - 1))
return null;

// Aumentamos el índice en una unidad y devolvemos ese elemento


else
return (Vehiculo)this.vehiculos[++posicionActual];
}
Finalmente, el método QuedanElementos() comprobará si nos encontramos en el
último elemento del listado o si, por el contrario, aún quedan elementos disponibles.

// Operación 4: Comprobación de si existen elementos en la colección


public bool QuedanElementos()
{
// Devolvemos un booleano que será true si la posición siguiente es menor o igual que el
// máximo índice aceptable (número de elementos del array - 1).
return (posicionActual + 1 <= this.vehiculos.Count - 1);
}
Et voilà! Ya tenemos listo nuestro Iterator. Únicamente nos queda algo por hacer: proporcionar a nuestro listado
RegistroVehiculos un método que nos genere un Iterator listo para ser utilizado con la colección contenida dentro de él. Es más,
ya que tenemos disponibles sus respectivas abstracciones (las interfaces IRegistroVehiculos e IIteratorVehiculo), añadiremos un
método a IRegistroVehiculo una función que nos devuelva una referencia a la interfaz IIteratorVehiculo, que será implementada
por RegistroVehiculos. Por lo tanto, nuestra interfaz IRegistroVehiculos tendrá el siguiente aspecto definitivo:

public interface IRegistroVehiculos


{
void InsertarVehiculo(string marca, string modelo, double precio);
Vehiculo MostrarInformacionVehiculo(int indice);
IIteratorVehiculo ObtenerIterator();
}
El método correspondiente dentro de RegistroVehiculos se limitará a instanciar un objeto de la clase IteratorVehiculo
(que recordemos que implementaba IIteratorVehiculo) inyectándole el ArrayList, devolviendo el objeto como resultado
de la función.
public IIteratorVehiculo ObtenerIterator()
{
return new IteratorVehiculo(listaVehiculos);
}
Para probar el resultado de nuestro patrón, nos bastará el siguiente ejemplo:
// Declaramos el registro
IRegistroVehiculos registro = new RegistroVehiculos();

// Insertamos unos cuantos elementos


registro.InsertarVehiculo("Volkswagen", "Polo", 12300);
registro.InsertarVehiculo("Volkswagen", "Golf GTI", 18900);
registro.InsertarVehiculo("Volkswagen", "Passat", 27000);
registro.InsertarVehiculo("Volkswagen", "Scirocco", 32100);
registro.InsertarVehiculo("Volkswagen", "Touareg", 21800);

// Obtenemos el iterator
IIteratorVehiculo iterador = registro.ObtenerIterator();

// Mientras queden elementos


while (iterador.QuedanElementos())
{
// Obtenemos el siguiente elemento
Vehiculo v = iterador.Siguiente();

// Mostramos su contenido
Console.WriteLine(v.Marca + " " + v.Modelo + " fabricado el " + v.FechaFabricacion.ToShortDateString() + " (" + v.Precio + " euros)");
}
Aplicación del patron Iterator
Este patrón, como podemos ver, no tiene demasiada complejidad: es más simple que la maquinaria de un
botijo. Sin embargo, la pregunta que seguramente ronde la cabeza del lector sea similar a “pero si
tenemos un ArrayList, ¿para qué recorrerlo secuencialmente? ¿Para qué usar esas comprobaciones
cuando pueden codificarse en nuestro código de forma sencilla? ¿No es rizar el rizo? La verdad es que sí.
Este patrón no está pensado para aplicarlo a una estructura de datos que ya posea mecanismos de acceso,
como por ejemplo el ArrayList que hemos utilizado aquí: está pensado para ser utilizado en estructuras en
los que el cliente no deba o no necesite conocer su estructura interna. Este ejemplo es estúpido porque
hemos observado “las tripas” de la clase RegistroVehiculos y sabemos que dentro de ella vive un ArrayList.
Pero si no lo supiéramos, el Iterator se encargaría de proporcionarnos acceso a sus miembros.
Vale, de acuerdo, en la ignorancia está la felicidad. Pero aún así, el programador original de la aplicación
sabe que dentro de RegistroVehiculos hay un ArrayList, independientemente de que el cliente necesite
saberlo o no. ¿Por qué complicarse la vida de esta manera? Porque ¿qué ocurriría si dentro de nuestra
estructura de datos no hubiese un ArrayList. O mejor aún: ¿qué ocurriría si nuestro cliente abriese una
fábrica en otra ciudad y nuestra aplicación necesitara conectarse de forma remota a la información allí
contenida? ¿Cambiaríamos todas nuestras clases e interfaces para proporcionar un conjunto de
operaciones que nos permitiera conectarnos de forma remota al nuevo centro? Con este patrón no sería
necesario. Bastaría con implementar otra vez la interfaz IIteratorVehiculo de forma que sus operaciones
realizaran las peticiones necesarias al servicio remoto, haciéndolo transparente para el usuario. Por
ejemplo, podríamos idear una implementación como la siguiente:
public class IteratorVehiculoRemoto : IIteratorVehiculo { request.Method = "GET";
private String urlServicio; // Obtenemos la respuesta
// Almacenaremos el índice en el que se encuentra el iterador WebResponse response = request.GetResponse();
private int posicionActual = -1; Stream data = response.GetResponseStream();
// El constructor inyectará la dirección del servicio en el objeto response.Close();
public IteratorVehiculoRemoto(String urlServicio) { // Deserializamos el objeto
this.urlServicio = urlServicio; } byte[] buffer = new byte[data.Length];
public void Primero() { data.Read(buffer, 0, buffer.Length);
this.posicionActual = -1; } MemoryStream ms = new MemoryStream(buffer);
public Vehiculo Actual() { IFormatter formatter = new BinaryFormatter();
WebRequest request = WebRequest.Create(urlServicio + "?Index=" + ms.Seek(0, SeekOrigin.Begin);
posicionActual); Vehiculo v = (Vehiculo)formatter.Deserialize(ms);
((HttpWebRequest)request).UserAgent = "Cliente IteratorVehiculoRemoto"; return v;
request.Method = "GET"; }
WebResponse response = request.GetResponse(); public bool QuedanElementos() {
Stream data = response.GetResponseStream(); WebRequest request = WebRequest.Create(urlServicio + "?
response.Close(); GetMaxElements");
// Deserializamos el objeto ((HttpWebRequest)request).UserAgent = "Cliente IteratorVehiculoRemoto";
byte[] buffer = new byte[data.Length]; request.Method = "GET";
data.Read(buffer, 0, buffer.Length); // Obtenemos la respuesta
MemoryStream ms = new MemoryStream(buffer); WebResponse response = request.GetResponse();
IFormatter formatter = new BinaryFormatter(); Stream data = response.GetResponseStream();
ms.Seek(0, SeekOrigin.Begin); response.Close();
Vehiculo v = (Vehiculo)formatter.Deserialize(ms); // Obtenemos el resultado de la petición
return v; StreamReader reader = new StreamReader(data);
} string strResultado = reader.ReadLine();
public Vehiculo Siguiente() { if(!string.IsNullOrEmpty(strResultado))
// Aquí realizaríamos las comprobaciones necesarias para determinar si la return Boolean.Parse(strResultado);
petición es válida return false;
// Realizamos la petición HTTP }
WebRequest request = WebRequest.Create(urlServicio + "?Index=" + (+ }
+posicionActual));
((HttpWebRequest)request).UserAgent = "Cliente IteratorVehiculoRemoto";
Como podemos ver, ambos iteradores serán IIteratorVehiculo, y como tales, tendrán los mismos métodos. Por lo tanto,
la clase cliente no necesitará saber si está obteniendo los datos desde un ArrayList de nuestra máquina o desde un
servicio web alojado en otra Comunidad Autónoma. La transparencia es la clave de este patrón, y por lo tanto, será el
objetivo que debemos buscar. Incluso podríamos crear un tercer Iterator que de algún modo fusionara ambos
iteradores, haciendo que cuando se llegara al final del iterador del ArrayList se comenzaran a proporcionar elementos
del servicio web, tratando ambas colecciones de cara al cliente como si fuera una sola.
Nota: el código que he mostrado para simbolizar la implementación de un iterador ejecutado sobre un servicio no es
real. Se trata de una simulación en la que se pretende mostrar, de forma conceptual, cómo podría implementarse el
patrón para acceder a elementos remotos. Ningún servicio web ha sido maltratado durante la redacción de este
artículo.

¿Cuándo utilizar este patrón? Ejemplos reales


Ya hemos visto cuándo es aconsejable utilizar este patrón: cuando queramos proporcionar una forma de iterar sobre
una colección sin que el cliente tenga que conocer los detalles de cómo está implementada. Por fortuna para nosotros,
no tendremos que crear una interfaz IIterator, ya que tanto Java como .NET ofrecen una interfaz estándar de la cual es
aconsejable que hereden los iteradores que decidamos implementar. Estas clases son IEnumerator en el caso de .NET e
Iterator en el caso de Java.
En el caso de .NET, la clase IEnumerator será la encargada de cumplir esta función. A diferencia del ejemplo anterior, no
posee un método QuedanElementos(). Sin embargo, esta funcionalidad está cubierta por el método MoveNext(), que
en lugar de devolver una referencia al elemento siguiente, comprueba si existen elementos y devuelve el resultado de
la consulta. Además, en caso afirmativo, incrementará el índice en una unidad, permitiendo al método Current()
acceder al siguiente elemento.
private class IteratorVehiculoEnumerable<T> : IEnumerator<T>  
{             // Devolvemos el elemento correspondiente al elemento actual
    // Referencia al listado completo             else
    private ArrayList listaElementos;                 return (T)this.listaElementos[posicionActual];
          }
    // Almacenaremos el índice en el que se encuentra el iterador     }
    private int posicionActual = -1;  
      object IEnumerator.Current
    // El constructor inyectará el ArrayList en el objeto     {
    public IteratorVehiculoEnumerable(ArrayList listaElementos)         get { return Current; }
    {     }
        this.listaElementos = listaElementos;  
    }     // La función ElementoSiguiente() de IEnumerable, a diferencia del ejemplo anterior, no devuelve una
      // referencia al siguiente elemento, sino que detecta si existe otro elemento (lo que en la
implementación
    public void Reset()
    // anterior realizaba QuedanElementos()) y en caso afirmativo, incrementa el índice, apuntando al
    {
siguiente
        this.posicionActual = -1;
    // elemento, que será recuperado mediante Current.
    }
    public bool MoveNext()
      {
    // Devuelve el elemento actual
        bool quedanElementos = (posicionActual + 1 <= this.listaElementos.Count - 1);
    public T Current
    {         if (quedanElementos)
        get             posicionActual++;
        {  
            // Si no existen elementos, devolveremos null.         return quedanElementos;
            // Si el indice actual es mayor que el mayor indice aceptable, devolveremos null.     }
            // Si el indice actual es -1, devolveremos null.
 
            if ((this.listaElementos == null) ||
    public void Dispose()
                (this.listaElementos.Count == 0) ||
    {
                (posicionActual > this.listaElementos.Count - 1) ||
        // Este método se implementará en caso de utilizar recursos no gestionados.
                (this.posicionActual < 0))
        // En ese caso, aquí se liberarán esos recursos antes de destruir el objeto.
                return default(T);         return;
    }
}
PATRONES DE COMPORTAMIENTO (II):
PATRÓN COMMAND
Objetivo:
“Encapsular una petición como un objeto, de modo que puedan parametrizarse
otros objetos con distintas peticiones o colas de peticiones y proporcionar soporte
para realizar operaciones que puedan deshacerse”.
• Cuando decimos que un patrón es “estructural” es sencillo imaginar que su
cometido será modelar las clases de tal forma que cumplan un cometido
concreto. Sin embargo, el concepto de diseñar clases orientando su
funcionalidad hacia el comportamiento es algo más complicado. El patrón
command u orden (como decía mi profesor de programación en primero de
carrera, command se debería traducir por órden, no por comando, ya que un
comando es un señor militar que pega tiros en la selva) tiene como objetivo
encapsular la invocación de un método. Dicho así sin más, suena sencillo de
entender pero… ¿cómo lo implementamos? La definición, a diferencia del
patrón anterior, es un conglomerado de términos incomprensibles, ¿verdad?
Encapsular una petición como un objeto. Vale, lo pillo. Pero ¿parametrizarse?
¿Soporte para realizar peticiones que puedan deshacerse?
• Entendiendo el patrón Command
• A estas alturas ya deberíamos de estar saturados del concepto de depender de abstracciones, no de
concreciones. Y por ello, seguramente nos sea mucho más sencillo entender este patrón si lo adaptamos
a un lenguaje más técnico y algo menos abstracto (principal objetivo de esta serie de artículos). Si
hacemos aterrizar este concepto al mundo real, podríamos traducirlo como lo siguiente:
• “Utilizar una interfaz con un método genérico de modo que los objetos que la implementen incluyan una
referencia al objeto cuyo método queremos abstraer. Al invocar el método genérico se invocará este
método, por lo que el objeto receptor no tiene por qué conocer el objeto original, bastándole una
referencia a la interfaz para ejecutar el método“.
• ¿Mejor así? Quizás sea todavía un poco complicado, ¿verdad? Intentemos desgranarlo un poco más.
• Si tenemos una interfaz común ICommand con un método genérico execute(), cualquier objeto que la
implemente podrá añadir dentro del código de execute() la llamada al método que queremos abstraer. De
este modo, el objeto receptor queda completamente desacoplado del objeto invocado. Le bastará con
invocar ICommand.execute() para que ocurra la magia. El cliente será el encargado de implementar las
clases adecuadas para asegurar la funcionalidad que el objeto receptor espera. Nuestro objeto receptor
puede ser una aplicación web esperando ejecutar una operación sobre una base de datos. Lo ideal sería
que nuestra aplicación no tuviera que preocuparse ni qué objeto usar para realizar la operación ni el
nombre de ésta. Si la interfaz ICommand proporciona un método genérico para realizar esta operación,
nuestros programadores podrán implementar tantos conectores a distintas bases de datos como quieran.
Nuestra aplicación simplemente dirá algo así como “a mí no me cuentes tu vida. No me interesa saber qué
hay más allá, yo ejecutaré el método ICommand.execute() y tú te encargas del resto del trabajo“.
Por lo tanto, podemos afirmar que el patrón Command es la quintaesencia de una
interfaz: ofrece la firma de un método genérico que las clases que la implementan se
encargarán de completar. Resumiendo, el patrón Command hace que la implementación
del método de una interfaz encapsule la invocación del método de otro objeto distinto.

Si nos centramos en el diagrama de clases del diseño del patrón, podremos identificar los
siguientes actores:
• ICommand: interfaz que expone el método genérico (execute()).
• CommandGenerico: implementa ICommand y posee una referencia al objeto cuyo
método execute() tendrá que encapsular. Este objeto recibe el nombre de Receiver.
• Receiver: como acabamos de decir, es el objeto que implementa la funcionalidad real.
Alguno de sus métodos será encapsulado por ICommand.execute().
• Invoker: clase encargada de invocar el método ICommand.execute(). Posee una
referencia (o varias) a ICommand, y su método SetCommand le permite cambiar su
funcionalidad en tiempo de ejecución. Ofrecerá también un método que invoque el
método ICommand.Execute() que, a su vez, invocará Receiver.MetodoAEncapsular().
Implementando el patrón Command
Volvamos a nuestra fábrica de vehículos. Se nos ha encargado programar parte de la centralita de un nuevo modelo,
concretamente de la activación y desactivación de las luces. Sabemos que contaremos con tres tipos de luces: posición,
cortas y largas, pero la implementación de los métodos encargados de este proceso aún no están definidas, ya que se han
subcontratado a una empresa coreana. Sin embargo, nuestro cliente nos exige que, pese a ello, debemos avanzar con el
diseño de este módulo.
El patrón Command es perfecto en este escenario: contamos con un entorno en el que debemos ejecutar un método que
aún no conocemos o que puede cambiar con el tiempo, por lo que crearemos una interfaz ICommand que exponga un
método Execute(). Posteriormente, una vez que los requisitos estén claros y que sepamos qué hay que ejecutar,
implementaremos clases que se acoplen entre nuestra centralita y el componente que la empresa coreana nos
proporcionará.
Por lo tanto, comenzaremos creando una interfaz ICommand que se encargará de ofrecer una firma para el método que
encapsulará el resto de los métodos: Execute():
public interface ICommand
{
// El método Execute() será aquel que el objeto que reciba la referencia
// será capaz de ejecutar.
void Execute();
}
A continuación modelaremos las clases que serán encapsuladas por el objeto Command. O más
específicamente, las clases cuyos métodos serán encapsulados por el método Execute() del objecto
Command(). Crearemos una clase abstracta de la que heredarán el resto de las clases que serán encapsuladas,
aunque en realidad esto no es estrictamente necesario (un objeto Command podría albergar diversos objetos
no necesariamente relacionados entre sí). Esta clase es conocida como Receiver, y se caracteriza porque se
encargará de albergar la lógica concreta del método. Si nos ceñimos a la descripción de una interfaz, la clase
Receiver sería aquella clase que se encargaría de implementarla.
// Clase abstracta de la que heredarán las clases que serán encapsuladas por los
// objectos Command. Por lo tanto, sus métodos serán aquellos que encapsulará el
// método Execute().
public abstract class LucesReceiver
{ A continuación implementaremos las clases concretas cuyos métodos
protected bool encendidas; serán encapsulados por ICommand.Execute(). Dado que heredan de la
protected int distanciaAlumbrado;
clase abstracta LucesReceiver, únicamente tendremos que implementar
// Propiedad de sólo lectura que devolverá el estado de las luces de forma explícita el método Encender(), ya que el resto de la
public bool Encendidas funcionalidad será común. Comenzaremos por las luces de posición:
{
get {return encendidas;}
}

// Método encargado de apagar las luces. Establece el estado del atributo 'encendidas'
// a 'false'. Será común a todas las clases que hereden de ella.
public void Apagar()
{
this.encendidas = false;
}

// El método Encender será distinto en cada una de las clases que hereden de esta clase.
public abstract int Encender();
}
public class LucesPosicion : public class LucesCortas : LucesReceiver
LucesReceiver {
{ private const int DISTANCIA = 40;
private const int DISTANCIA = 1; public override int Encender() {
public override int Encender() { this.encendidas = true;
return DISTANCIA;
this.encendidas = true;
}
return DISTANCIA; }
}
}

public class LucesLargas : LucesReceiver Esto se resumiría ahora mismo en el siguiente


{ esquema:
private const int DISTANCIA = 200;

public override int Encender()


{
this.encendidas = true;
return DISTANCIA;
}
}
Ya tenemos implementado uno de los elementos de nuestro patrón. Ahora haremos lo propio con la parte cliente,
es decir, nuestra centralita. O más concretamente, el módulo encargado de encender y apagar las luces. Este se
corresponderá con el elemento Invoker, que es aquel que tendrá como objetivo invocar la acción encapsulada por el
objeto Command. Comenzaremos implementando una interfaz que ofrezca dos operaciones:
Una operación SetCommand(ICommand) que permitirá a nuestro módulo cambiar el ICommand a ejecutar.
Una operación Invoke() que invoque el método ICommand.Execute() que esté asignado en el momento actual.

public interface IInvoker{


// Inyecta un ICommand, permitiendo cambiar la operación encapsulada en
// tiempo de ejecución
void SetCommand(ICommand command);

// Ejecuta el método encapsulado


void Invoke();
}
A continuación implementaremos la interfaz. Lo haremos a través de la clase ControladorLucesInvoker. Nuestra clase
realizará justo aquello que acabamos de definir en la interfaz. Además, incluirá una referencia a un objeto que
implemente la interfaz ICommand
public class ControladorLucesInvoker : IInvoker Ya casi hemos completado nuestro patrón. Falta lo más
{ importante: las clases que implementan la clase ICommand y
ICommand command; que simbolizan las operaciones que se quieren encapsular.
Estas operaciones serán, como podemos imaginar, encender y
public void SetCommand(ICommand command) apagar. Por lo tanto, crearemos las clases
{ EncenderLucesCommand
this.command = command; y ApagarLucesCommand:
}
public class EncenderLucesCommand : ICommand
{
public void Invoke() // Referencia al objeto cuyo método se quiere encapsular
{ private LucesReceiver luces;
command.Execute(); // El constructor inyectará el objeto cuyo método se quiere encapsular
public EncenderLucesCommand(LucesReceiver luces) {
}
this.luces = luces; }
}
// El método Execute() ejecutará el método encapsulado
public void Execute() {
int distancia = luces.Encender();
Console.WriteLine(string.Format("Encendiendo luces. Alumbrando a una distancia de {0} metros.",
distancia));
}
}
public class ApagarLucesCommand : ICommand
{
private LucesReceiver luces;

public ApagarLucesCommand(LucesReceiver luces)


{
this.luces = luces;
}

public void Execute()


{
luces.Apagar();
Console.WriteLine("Apagando las luces");
}
}

Esto completará nuestro diagrama de clases, dejándolo de la


siguiente manera:
Finalmente, añadimos el código que hará uso del patrón que
acabamos de implementar. En él crearemos los tres tipos de
luces (posición, cortas y largas) y utilizaremos el método
SetCommand() de cada uno de los objetos destinados a encender
y a apagar las luces para cambiar en tiempo de ejecución el tipo
de luz a manejar.
// Instanciamos los objetos cuyos métodos serán encapsulados dentro de
// objetos que implementan ICommand
LucesReceiver lucesPosicion = new LucesPosicion();
LucesReceiver lucesCortas = new LucesCortas();
LucesReceiver lucesLargas = new LucesLargas();
 
// Creamos los objetos Command que encapsulan los métodos de las clases anteriores
ICommand encenderPosicion = new EncenderLucesCommand(lucesPosicion);
ICommand apagarPosicion = new ApagarLucesCommand(lucesPosicion);
 
ICommand encenderCortas = new EncenderLucesCommand(lucesCortas);
ICommand apagarCortas = new ApagarLucesCommand(lucesCortas);
 
ICommand encenderLargas = new EncenderLucesCommand(lucesLargas);
ICommand apagarLargas = new ApagarLucesCommand(lucesLargas);
 
// Creamos un nuevo Invoker (el objeto que será desacoplado de las luces)
IInvoker invoker = new ControladorLucesInvoker(); // Le asociamos los objetos Command y los ejecutamos
// El objeto invoker invoca el método 'Execute()' sin saber en ningún momento
// qué es lo que se está ejecutando realmente.
invoker.SetCommand(encenderPosicion);      // Asociamos el ICommand
invoker.Invoke();                          // Hacemos que se ejecute ICommand.Execute()
 
// Realizamos lo mismo con el resto de instancias que implementan ICommand.Como podemos ver, el ICommand puede asignarse en tiempo de ejecucion
invoker.SetCommand(apagarPosicion);
invoker.Invoke();
 
// Luces cortas
invoker.SetCommand(encenderCortas);
invoker.Invoke();
invoker.SetCommand(apagarCortas);
invoker.Invoke();
 
// Luces largas
invoker.SetCommand(encenderLargas);
invoker.Invoke();
 invoker.SetCommand(apagarLargas);
invoker.Invoke();
¿Cuándo utilizar este patrón? Ejemplos reales
Dado que este patrón nos permite encapsular la ejecución de un método como un objeto, una de
las funcionalidades que nos ofrece este patrón es la de encadenar invocaciones. Si creamos una
serie de objetos de este tipo y los almacenamos como objetos, éstos pueden pasarse como
parámetros a un método que los vaya ejecutando de forma secuencial.
El segundo escenario en el que este patrón es útil es aquel que hemos visto en el ejemplo, es decir,
aquel en el que el invocador del método deba ser desacoplado del objeto que maneja la
invocación. Esto puede darse por necesidades del diseño o bien porque las especificaciones del
módulo que maneja la invocación no estén definidas o existe previsión de que vaya a variar con el
tiempo.
Recordemos además que la definición del patrón establecía que debía proporcionar soporte para
deshacer operaciones. ¿Cómo realizar esto? Dado que estas operaciones se encapsulan como
objetos, sería perfectamente posible mantener en memoria una pila con elementos ejecutados y
otra que almacene objetos que modelen los distintos estados correspondientes a los instantes
anteriores a ejecutar cada uno de los Commands de la primera pila. De este modo, realizar la opción
deshacer sería tan sencillo como realizar un pop del primer objeto de cada pila y sobreescribir el
estado actual del programa con el contenido del primer objeto almacenado en la pila de estados.
Otros ejemplos reales de este patrón serían, por ejemplo:
• Grabación de macros (secuencia de operaciones)
• Asistentes de instalación (cada pantalla implementaría un Command que realizaría una operación
Execute() al pulsar el botón “Siguiente”)
• Elementos Action del framework Swing de Java.
• MVVM Xamarin. Ejemplo de Command. Binding.
• MVVM
PATRONES DE COMPORTAMIENTO (III):
TEMPLATE METHOD
Objetivo: “Permitir que ciertos pasos de un algoritmo definidos en un
método de una clase sean redefinidos en sus clases derivadas sin
necesidad de sobrecargar la operación entera”.
Si el patrón Command nos permite encapsular una invocación a un método, el patrón Template Method o Método
Modelo establece una forma de encapsular algoritmos. Este patrón se basa en un principio muy sencillo: si un algoritmo
puede aplicarse a varios supuestos en los que únicamente cambie un pequeño número de operaciones, la idea será
utilizar una clase para modelarlo a través de sus operaciones. Esta clase base se encargará de definir los pasos comunes
del algoritmo, mientras que las clases que hereden de ella implementarán los detalles propios de cada caso concreto, es
decir, el código específico para cada caso.

El procedimiento es sencillo:
• Se declara una clase abstracta, que será la plantilla o modelo. Esta clase definirá una serie de funciones y métodos.
Aquellas que sean comunes estarán implementadas. Aquellas que dependan de cada caso concreto, se declararán
como abstractas, obligando a las clases hijas a implementarlas.
• Cada clase derivada implementará los métodos específicos, acudiendo a la clase base para ejecutar el código común.
• La clase base también se encargará de la lógica del algoritmo, ejecutando los pasos en un orden preestablecido (las
clases hijas no deberían poder modificar el algoritmo, únicamente definir la funcionalidad específica que tienen que
implementar).

Dado que la clase padre es la que se encarga de llamar los métodos de las clases derivadas (los pasos del algoritmo
estarán implementado en la clase base), se trata de una aplicación manifiesta del principio de inversión de dependencias:
la clase base no tiene por qué saber nada acerca de sus hijas, pero aún así, se encargará de invocar su funcionalidad
cuando sea necesario. El principio de Hollywood (“no nos llames, nosotros te llamaremos”) vuelve a entrar en escena.
Implementando el patrón
En anteriores artículos hemos hecho uso de este patrón sin ser conscientes de ello al definir el funcionamiento de un motor de cuatro
tiempos. Veíamos que el funcionamiento de un motor de gasolina se basaba en el siguiente algoritmo:
• Admisión: el descenso del pistón crea un vacío que aspira la mezcla de aire y combustible de la válvula de admisión. La válvula de
escape permanece cerrada.
• Compresión: una vez que el pistón ha bajado hasta el final, se cierra la válvula de admisión. El pistón asciende, comprimiendo la
mezcla y aumentando la presión.
• Explosión: el pistón alcanza la parte superior y la bujía produce una chispa que hace explotar la mezcla de aire y combustible,
haciendo que el pistón vuelva a descender.
• Escape: la válvula de escape se abre. El pistón asciende nuevamente, empujando los gases resultantes de la explosión y comenzando
un nuevo ciclo.

Ahora veamos cómo funciona, a grandes rasgos, un motor diesel de cuatro tiempos:
• Admisión: el descenso del pistón crea un vacío que aspira aire desde la válvula de admisión. La válvula de escape permanece
cerrada.
• Compresión: una vez que el pistón ha bajado hasta el final, se cierra la válvula de admisión. El pistón asciende, comprimiendo el
aire y aumentando la presión.
• Combustión: los inyectores pulverizan el combustible, haciendo que la presión se encargue de aumentar la temperatura, haciendo
que se produzca la combustión y la expansión de los gases que fuerzan el descenso del pistón.
• Escape: la válvula de escape se abre. El pistón asciende nuevamente, empujando los gases resultantes de la explosión y comenzando
un nuevo ciclo.

Tal y como observamos, ambos motores tienen un funcionamiento muy similar. Las fases 2 y 4 (compresión y escape) son idénticas, la
fase 1 (admisión) varía ligeramente, mientras que la fase 3 (explosión en el motor de gasolina, combustión en el motor diesel) tiene un
comportamiento diferente. ¿Cómo encaja aquí el patrón Template Method?
Dado que el algoritmo para realizar el ciclo del motor tiene los mismos pasos efectuados en el mismo orden, es el contexto
adecuado para utilizar este patrón. Podemos crear una superclase Motor que implemente las fases comunes a ambos
motores (Compresión, Escape) más el algoritmo RealizarFaseMotor, que será el encargado de invocar los métodos en un
orden fijo. Esta ejecución será invariable, por lo que las clases derivadas únicamente podrán (y deberán) implementar las
partes específicas de cada motor.

Dado que la fase Admisión varía ligeramente (inyección de mezcla de combustible y gas en el motor de gasolina frente a
inyección de gas en el motor diesel), es posible implementar la parte común en el propio método de la superclase y
encapsular únicamente la parte que varía en otro método que será invocado desde Compresión. Así respetaremos otro de
los principios de la orientación a objetos: encapsular aquello que es susceptible de cambiar.

Comencemos creando la clase abstracta Motor. Si bien en otros casos hemos hablado de utilizar una interfaz o una clase
abstracta para implementar una abstracción, en este caso será necesario utilizar una clase abstracta, no una interfaz.
¿Por qué? Porque si utilizamos una interfaz únicamente podremos definir la firma de los métodos a utilizar, pero no
podremos codificar una funcionalidad común, que es lo que pretende este patrón. Por lo tanto, Motor será una clase
abstracta que implementará de forma explícita la parte común y declarará como abstractos los métodos que las clases
derivadas estarán obligadas a implementar.

Comenzaremos declarando unas cuantas variables: dos para modelar el estado de las válvulas y otras dos para modelar el
ángulo actual del cigüeñal y del árbol de levas. También crearemos un método que “reinicie” el ángulo de estos dos
elementos, manteniéndolos siempre entre 0 y 359 grados:
public abstract class Motor A continuación modelaremos los dos métodos que
{
    // Estado de las válvulas implementará de forma explícita la clase base: compresión y
    private bool valvulaAdmisionAbierta = false; escape:
    private bool valvulaEscapeAbierta = false;
  // Segunda Fase: Compresión
    // Ángulos del cigueñal y del árbol de levas protected void Compresion() {
    protected int anguloCiguenal = 0; Console.WriteLine("COMENZANDO FASE DE COMPRESION");
    protected int anguloArbolLevas = 0; // Se cierra la válvula de admisión
valvulaAdmisionAbierta = false;
 
// Giros del cigueñal y del árbol de levas
  anguloCiguenal = SumarAngulo(anguloCiguenal, 360);
    // Método que mantendrá el ángulo entre 0 y 359 grados
anguloArbolLevas = SumarAngulo(anguloArbolLevas, 180);
    protected int SumarAngulo(int anguloActual, int cantidad)
Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);
    {
Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas);
        if (anguloActual + cantidad >= 360)
Console.WriteLine("Valvula de admision abierta: " + valvulaAdmisionAbierta);
            return anguloActual + cantidad - 360; Console.WriteLine("Valvula de escape abierta: " + valvulaEscapeAbierta + "\n");
        else }
            return anguloActual + cantidad; // Cuarta Fase: Escape
    } protected void Escape() {
  Console.WriteLine("COMENZANDO FASE DE ESCAPE");
} // Se abre la válvula de escape
valvulaEscapeAbierta = true;
// Giros del cigueñal y del árbol de levas
anguloCiguenal = SumarAngulo(anguloCiguenal, 180);
anguloArbolLevas = SumarAngulo(anguloArbolLevas, 90);
Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);
Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas);
Console.WriteLine("Gases expulsados. Fin de ciclo");
}
Hemos dicho que la tercera fase depende exclusivamente de
las clases derivadas. Por lo tanto, nuestra clase motor se // La bajada del pistón depende del motor concreto, por lo que deberá ser implementada
// por la clase hija.
limitará a declarar el método como abstracto y obligar a las protected abstract void BajarPiston();
clases derivadas a implementar la funcionalidad específica  
// Primera Fase: Admisión
de cadNos queda la primera fase: admisión. Hemos dicho protected void Admision()
que parte de la funcionalidad es común (bajada del pistón, {
    Console.WriteLine("COMENZANDO FASE DE ADMISION");
apertura de la válvula de admisión), pero otra parte  
depende de si el motor es de gasolina (inyección de     // Se abre la válvula de admisión y se cierra la válvula de escape
    valvulaAdmisionAbierta = true;
combustible y aire) o diesel (inyección de aire). Por tanto,     valvulaEscapeAbierta = false;
creamos otro método abstracto que las clases hija tendrán  
    // Se baja el pistón. Esta operación será distinta en el motor diesel (que
que codificar (BajarPiston()) y se invoca desde el método     // inyectará aire) o gasolina (que inyectará una mezcla de aire y combustible)
Admision(), que codificará la parte común:a motor:     BajarPiston();
 
// Tercera Fase: Consumo del combustible. Dado que depende del motor concreto,     anguloCiguenal = SumarAngulo(anguloCiguenal, 180);
// este método será abstracto y deberá ser implementado por la clase derivada.     anguloArbolLevas = SumarAngulo(anguloArbolLevas, 90);
protected abstract void ConsumirCombustible();  
    Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);
    Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas);
 
    Console.WriteLine("Valvula de admision abierta: " + valvulaAdmisionAbierta);
    Console.WriteLine("Valvula de escape abierta: " + valvulaEscapeAbierta + "\n");
}
Finalmente, codificamos el propio algoritmo, de carácter público, que
se encargará de invocar todos los pasos en un orden determinado:
// Método público que ejecutará el algoritmo completo
public void RealizarFaseMotor()
{
    Admision();             // Parcialmente implementado en la clase base
    Compresion();           // Implementado en la clase base
    ConsumirCombustible();  // Delegado en las clases hijas
    Escape();               // Implementado en la clase base
}

La clase completa, por lo tanto, tendrá el


siguiente aspecto:
public abstract class Motor // Segunda Fase: Compresión
{ protected void Compresion() {
// Estado de las válvulas Console.WriteLine("COMENZANDO FASE DE COMPRESION");
private bool valvulaAdmisionAbierta = false; // Se cierra la válvula de admisión
private bool valvulaEscapeAbierta = false; valvulaAdmisionAbierta = false;
// Ángulos del cigueñal y del árbol de levas // Giros del cigueñal y del árbol de levas
protected int anguloCiguenal = 0; anguloCiguenal = SumarAngulo(anguloCiguenal, 360);
protected int anguloArbolLevas = 0; anguloArbolLevas = SumarAngulo(anguloArbolLevas, 180);
// Método público que ejecutará el algoritmo completo Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);
public void RealizarFaseMotor() { Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas);
Admision(); // Parcialmente implementado en la clase base Console.WriteLine("Valvula de admision abierta: " + valvulaAdmisionAbierta);
Compresion(); // Implementado en la clase base Console.WriteLine("Valvula de escape abierta: " + valvulaEscapeAbierta + "\n");
ConsumirCombustible(); // Delegado en las clases hijas }
Escape(); // Implementado en la clase base // Tercera Fase: Consumo del combustible. Dado que depende del motor concreto,
} // este método será abstracto y deberá ser implementado por la clase derivada.
// Primera Fase: Admisión protected abstract void ConsumirCombustible();
protected void Admision() { // Cuarta Fase: Escape
Console.WriteLine("COMENZANDO FASE DE ADMISION"); protected void Escape() {
// Se abre la válvula de admisión y se cierra la válvula de escape Console.WriteLine("COMENZANDO FASE DE ESCAPE");
valvulaAdmisionAbierta = true; // Se abre la válvula de escape
valvulaEscapeAbierta = false; valvulaEscapeAbierta = true;
// Se baja el pistón. Esta operación será distinta en el motor diesel (que // Giros del cigueñal y del árbol de levas
// inyectará aire) o gasolina (que inyectará una mezcla de aire y combustible) anguloCiguenal = SumarAngulo(anguloCiguenal, 180);
BajarPiston(); anguloArbolLevas = SumarAngulo(anguloArbolLevas, 90);
anguloCiguenal = SumarAngulo(anguloCiguenal, 180); Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);
anguloArbolLevas = SumarAngulo(anguloArbolLevas, 90); Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas);
Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal); Console.WriteLine("Gases expulsados. Fin de ciclo");
Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas); }
Console.WriteLine("Valvula de admision abierta: " + valvulaAdmisionAbierta); // Método que mantendrá el ángulo entre 0 y 359 grados
Console.WriteLine("Valvula de escape abierta: " + valvulaEscapeAbierta + "\n"); protected int SumarAngulo(int anguloActual, int cantidad) {
} if (anguloActual + cantidad >= 360)
return anguloActual + cantidad - 360;
// La bajada del pistón depende del motor concreto, por lo que deberá ser implementada else
// por la clase hija. return anguloActual + cantidad;
protected abstract void BajarPiston(); }
Una vez que tenemos la clase padre, implementaremos las clases derivadas:
MotorGasolina y MotorDiesel. Únicamente tendrán que implementar las partes
específicas, es decir, los métodos BajarPiston() y ConsumirCombustible():

public class MotorGasolina : Motor public class MotorDiesel : Motor


{ {
    protected override void BajarPiston()     protected override void BajarPiston()
    {     {
        Console.WriteLine("Inyectando aire y combustible en el motor");         Console.WriteLine("Inyectando aire en el motor");
    }     }
   
    public override void ConsumirCombustible()     protected override void ConsumirCombustible()
    {     {
        Console.WriteLine("COMENZANDO FASE DE EXPLOSIÓN");         Console.WriteLine("COMENZANDO FASE DE COMBUSTIÓN");
   
        Console.WriteLine("Iniciando chispa en la bujía");         Console.WriteLine("Inyectando combustible pulverizado en el motor");
        Console.WriteLine("La explosión provoca el movimiento del pistón");         Console.WriteLine("La presión provoca el movimiento del pistón");
   
        anguloCiguenal = SumarAngulo(anguloCiguenal, 180);         anguloCiguenal = SumarAngulo(anguloCiguenal, 180);
        anguloArbolLevas = SumarAngulo(anguloArbolLevas, 90);         anguloArbolLevas = SumarAngulo(anguloArbolLevas, 90);
   
        Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);         Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);
        Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas + "\n");          Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas + "\n");           
    }     }
} }
Tal y como hemos dicho, las dos diferencias entre ambos radican en la compresión (inyección de
mezcla en el motor gasolina por inyección de aire en el motor diesel) y en el consumo de
combustible (explosión en el motor gasolina por combustión en el motor diesel). Salvando los
detalles concretos que hemos codificado, el algoritmo del motor es exactamente el mismo, y viene
determinado por el método público codificado en la clase base RealizarFaseMotor(). De hecho, si
usamos el método para comprobar el funcionamiento de ambos motores, veremos el resultado:
Motor mGasolina = new MotorGasolina();
Motor mDiesel = new MotorDiesel();
 
mGasolina.RealizarFaseMotor();
Console.WriteLine("----------------------------------------------------");
mDiesel.RealizarFaseMotor()
Algoritmos con gancho
Lo que hemos visto hasta ahora es sencillo de entender y de implementar, pero probablemente nos hayamos dado cuenta de
un pequeño detalle: es demasiado rígido. La idea de mantener encapsulado e inmutable el cuerpo del algoritmo evita efectos
indeseados, pero limita muchísimo la posibilidad de añadir pasos intermedios. Por ejemplo, ¿qué ocurriría si nuestro motor
fuera turbo? El turbo realiza una compresión del aire antes de introducirlo en la cámara de explosión, proporcionando una
mayor potencia sin modificar la cilindrada del motor. Sin embargo, este paso estaría (que me disculpen los profesionales del
motor por lo que voy a decir) justo antes de la admisión. Sin embargo… habrá motores que implementen turbo y que no lo
implementen. ¿Creamos por tanto una clase MotorTurboGasolina y MotorTurboDiesel? ¿Hacemos también abstracto el
método Admisiónpara que este funcionamiento pueda personalizarse en las clases hijas? No es necesario. Para este tipo de
situaciones, el patrón proporciona lo que se conocen como Hooks, métodos de enganche o ganchos.
La filosofía de estos métodos es sencilla: se implementan en la clase base con un comportamiento por defecto, que puede
ser sobrecargado en las clases derivadas o ejecutado como está. De este modo, se proporcionan pasos opcionales, haciendo
que las clases derivadas enganchen funcionalidad opcional en ciertos puntos del algoritmo. Estos hooks suelen utilizarse
normalmente con cláusulas condicionales, de forma que se ejecuten en ciertas condiciones concretas.
protected virtual void ComprimirTurbo()
Al ser declarado como virtual, el método puede ser
{ En nuestro caso, añadiríamos un nuevo paso a nuestro algoritmo, al que llamaríamos ComprimirTurbo(), que
implementaríamos no
    Console.WriteLine("Turbo enpresente"); sobrecargado
la clase con un comportamiento en las clases derivadas. Así, modificaremos
por defecto:
}
// Método público que ejecutará el algoritmo completo nuestro motor diesel para que permita instanciar un motor turbo
public void RealizarFaseMotor() de la siguiente manera:
{
    ComprimirTurbo();       // Hook (método opcional)
    Admision();             // Parcialmente implementado en la clase base
    Compresion();           // Implementado en la clase base
    ConsumirCombustible();  // Delegado en las clases hijas
    Escape();               // Implementado en la clase base
}
public class MotorDiesel : Motor
{
El motor gasolina no será modificado, de modo que ejecutará el método por defecto
    private bool turbo = false; (no se “enganchará” al método ComprimirTurbo). Si ahora modificamos nuestro
 
    public MotorDiesel(bool turbo)
programa para instanciar un motor diesel turbo de la siguiente manera:
    {
        this.turbo = turbo;
    }
 
    protected override void ComprimirTurbo()
    {
        // Si el coche es turbo, ejecutará su propio código. En caso contrario, efectuará
        // la operación por defecto Motor mGasolina = new MotorGasolina();
        if (turbo) Motor mDiesel = new MotorDiesel(true);
            Console.WriteLine("Comprimiendo aire en el turbo antes de la admisión");  
        else
mGasolina.RealizarFaseMotor();
            base.ComprimirTurbo();
    } Console.WriteLine("----------------------------------------------------");
  mDiesel.RealizarFaseMotor();
    protected override void BajarPiston()
    {
        Console.WriteLine("Inyectando aire en el motor");
    }
 
    protected override void ConsumirCombustible()
    {
        Console.WriteLine("COMENZANDO FASE DE COMBUSTIÓN");
 
        Console.WriteLine("Inyectando combustible pulverizado en el motor");
        Console.WriteLine("La presión provoca el movimiento del pistón");
 
        anguloCiguenal = SumarAngulo(anguloCiguenal, 180);
        anguloArbolLevas = SumarAngulo(anguloArbolLevas, 90);
 
        Console.WriteLine("Angulo del ciguenal: " + anguloCiguenal);
        Console.WriteLine("Angulo del arbol de levas: " + anguloArbolLevas + "\n");           
    }
}
¿Cuándo utilizar este patrón? Ejemplos reales
Este patrón es aconsejable en los siguientes supuestos:
• Cuando se cuenta con un algoritmo aplicable a varias situaciones, cuya implementación
difiere únicamente en algunos pasos.
• Arquitecturas donde los pasos de un proceso estén definidos (el qué), pero sea necesario
establecer los detalles sobre cómo realizarlos (el cómo).
• Módulos en los que exista una gran cantidad de código duplicado que pueda ser factorizado
en pasos comunes.
Uno de los ejemplos más claros del uso de este patrón se da en los Servlets de Java. En ellos
se produce una invocación secuencial de los métodos init() (al instanciar el Servlet) y service()
(al realizar una petición) que, a partir del tipo de petición, ejecutarán el método
correspondiente a su tipo, como doGet(), doPost()… Estos métodos son los que el
programador deberá implementar para darles una funcionalidad concreta.
Otro ejemplo podría ser la ejecución de una transacción en base de datos: los pasos estarán
bien definidos (apertura de la conexión, ejecución de la consulta, procesamiento de los
datos, compromiso de la operación y cierre de la conexión), pero la implementación de éstos
podría variar (por ejemplo, dependiendo de la base de datos a la cual se pretenda conectar).
PATRONES DE COMPORTAMIENTO (IV):
PATRÓN STRATEGY
• Objetivo: “Definir una familia de algoritmos, encapsular cada uno de
ellos y hacerlos intercambiables. Strategy permite cambiar el
algoritmo independientemente de los clientes que lo utilicen”.
En el artículo anterior veíamos cómo un patrón de diseño puede ayudarnos a encapsular distintos
algoritmos a partir de una “plantilla” cuyos hijos se encargaban de especializar. El patrón Strategy,
por su parte, no bucea en los detalles, sino que va un paso más allá: encapsulará un algoritmo
completo ignorando los detalles de su implementación, permitiendo intercambiarlo en tiempo de
ejecución para permitir actuar a la clase cliente con un comportamiento distinto.
El nombre de este patrón evoca la posibilidad de realizar un cambio de estrategia en tiempo de
ejecución sustituyendo un objeto que se encargará de implementarla. No nos preocupará el
“cómo”. De hecho, ni siquiera nos importará “el qué”: la clase que actúa como interfaz del patrón
únicamente tendrá que exponer el método o métodos que deberá invocar el cliente.
Strategy pattern y videojuegos
Un ejemplo clásico para entender este patrón es el de un protagonista de un videojuego en el cual manejamos a un
soldado que puede portar y utilizar varias armas distintas. La clase (o clases) que representan a nuestro soldado no
deberían de preocuparse de los detalles de las armas que porta: debería bastar, por ejemplo, con un método de interfaz
“atacar” que dispare el arma actual y otro método “recargar” que inserte munición en ésta (si se diera el caso). En un
momento dado, otro método “cambiarArma” podrá sustituir el objeto equipado por otro, manteniendo la interfaz intacta.
Da igual que nuestro soldado porte un rifle, una pistola o un fusil: los detalles de cada estrategia estarán encapsulados
dentro de cada una de las clases intercambiables que representan las armas. Nuestra clase cliente (el soldado)
únicamente debe preocuparse de las acciones comunes a todas ellas: atacar, recargar y cambiar de arma. Éste último
método, de hecho, será el encargado de realizar la operación de “cambio de estrategia” que forma parte del patrón.
Por lo tanto, el patrón Strategy es, como podemos imaginar, uno de los patrones más utilizados a la hora de diseñar
software. Siempre que exista una posibilidad de realizar una tarea de distintas formas posibles, el patrón Strategy tendrá
algo que decir al respecto.
Nuestro diagrama de clases muestra una interfaz denominada IStrategy que expone un método operacion(). Las clases
que implementen esta interfaz serán aquellas que implementen las distintas estrategias a realizar por el cliente, y como
podemos observar, no tienen mayor dificultad: una interfaz, varias clases que la implementan. Programación Orientada a
Objetos básica.
La filosofía del patrón, por lo tanto, radica en el enlace entre la llamada clase de contexto y la propia interfaz. Esta clase
de contexto será el “broker” o intermediario entre el cliente y las clases que implementan la estrategia, y por lo tanto, sus
funciones serán simples: cambiar la estrategia actual y ejecutarla. Si hablásemos de un videojuego, el contexto sería el
objeto encargado de equipar la pistola al pulsar la tecla “1” y de invocar la funcionalidad de disparo cuando hacemos click
con el ratón. Esto se traduciría por instanciar un objeto StrategyPistola en la referencia IStrategy e invocar el método
“atacar()” de ésta para que la clase que implementa la interfaz se encargue del trabajo sucio (¡nunca mejor dicho!).
Implementando el patrón
Pese a que el ejemplo de nuestro videojuego es bastante ilustrativo, dado que en esta serie de artículos
tenemos fijación por los coches, implementaremos el patrón a través de un hipotético módulo de la centralita
del vehículo que nos permitirá alternar entre una conducción normal y deportiva. La diferencia entre ambas
será simple: mayor consumo, mayor potencia y mayor velocidad. Podríamos añadir más comportamientos
“personalizados”, como el endurecimiento de la suspensión, pero con estos dos elementos será suficiente para
captar la idea.
Comencemos añadiendo la interfaz ITipoConduccion, que simbolizará la interfaz de la estrategia (IStrategy). Le
añadiremos tres métodos: uno para obtener la descripción del tipo de conducción actual, otro que proporcione
el incremento de velocidad en relación al combustible inyectado y un tercer método que indique la cantidad de
potencia suministrada por el motor, también en proporción al combustible que recibe.

public interface ITipoConduccion


{ A continuación añadiremos las estrategias en sí, es decir, las clases que
    string ObtenerDescripcion(); implementan la interfaz y dotan de distintos comportamientos que serán
    int ObtenerPotencia(float decilitrosCombustible); seleccionados por el contexto. Habíamos dicho que utilizaríamos dos:
    int ObtenerIncrementoVelocidad(float decilitrosCombustible); conducción normal y conducción deportiva. Por lo tanto, crearemos dos
} clases que proporcionen distintos comportamientos para los mismos
métodos:
public class ConduccionNormal : ITipoConduccion public class ConduccionDeportiva : ITipoConduccion
{ {
    public string ObtenerDescripcion()     public string ObtenerDescripcion()
    {     {
        return "Conduccion Normal";         return "Conduccion Deportiva";
    }     }
   
    public int ObtenerPotencia(float decilitrosCombustible)     public int ObtenerPotencia(float decilitrosCombustible)
    {     {
        return (int)(decilitrosCombustible * 0.842) + 3;         return (int)(decilitrosCombustible * 0.987) + 5;
    }     }
   
    public int ObtenerIncrementoVelocidad(float decilitrosCombustible)     public int ObtenerIncrementoVelocidad(float decilitrosCombustible)
    {     {
        return (int)(decilitrosCombustible * 0.422) + 2;         return (int)(decilitrosCombustible * 0.618) + 3;
    }     }
} }

Lo siguiente será crear el contexto. Esta clase será la encargada de establecer la conexión entre el cliente y las clases que
implementan la estrategia, sustituyendo la clase que la implementa dependiendo del comportamiento esperado. Por lo tanto, se
compondrá de una referencia a la interfaz que implementarán las estrategias más un método que permita cambiar de instancia (es
decir, una property o un setter de toda la vida). A partir de esta funcionalidad básica, el contexto podrá realizar otras operaciones
relacionadas con la estrategia que pretende modelar, como por ejemplo la invocación de sus métodos o la encapsulación del cambio
de estrategia.
public class Contexto
{
En realidad, la propia clase cliente puede actuar como clase de
    // Referencia a la interfaz contexto, pero siempre será mejor minimizar el acoplamiento
    private ITipoConduccion tipoConduccion;
entre las estrategias y las reglas de negocio. De este modo,
 
    // Propiedad que establecerá un nuevo tipo de conducción (cambio de estrategia) respetaremos otro de los principios de la orientación a objetos:
    public ITipoConduccion TipoConduccion una clase, una responsabilidad. Para comprobar el
    {
        get { return tipoConduccion; }
funcionamiento de nuestro cliente, bastará con utilizar el
        set { this.tipoConduccion = value; } siguiente código que hará uso del contexto para cambiar de
    }
estrategia en tiempo de ejecución:
 
    // Métodos de servicio (invocan los métodos implementados por las estrategias)
    public string ObtenerDescripcion()
    {
        return tipoConduccion.ObtenerDescripcion();
    }
 
    public int IncrementarVelocidad(float combustible)
    {
        return tipoConduccion.ObtenerIncrementoVelocidad(combustible);
    }
 
    public int IncrementarPotencia(float combustible)
    {
        return tipoConduccion.ObtenerPotencia(combustible);
    }
}
public class Vehiculo Finalmente, el código que invoca a nuestro cliente, que será el siguiente:
{
    private Contexto contexto;
 
    public Vehiculo()
static void Main(string[] args)
    {
{
        contexto = new Contexto();
    Vehiculo v = new Vehiculo();
    }
    v.ConduccionDeportiva();
      v.Acelerar(2.4f);
    public void ConduccionDeportiva()  
    {     Console.WriteLine("");
        ITipoConduccion conduccionDeportiva = new ConduccionDeportiva();  
        contexto.TipoConduccion = conduccionDeportiva;     v.ConduccionNormal();
    }     v.Acelerar(2.4f);
   
    public void ConduccionNormal()     Console.ReadLine();
    { }
        ITipoConduccion conduccionNormal = new ConduccionNormal();
        contexto.TipoConduccion = conduccionNormal;
    }
 
    // Métodos que invocan la funcionalidad implementada por la interfaz
    public void Acelerar(float combustible)
    {
        string descripcion = contexto.ObtenerDescripcion();
        int incrementoVelocidad = contexto.IncrementarVelocidad(combustible);
        int potencia = contexto.IncrementarPotencia(combustible);
 
        Console.WriteLine("Tipo de conducción " + descripcion);
        Console.WriteLine("Combustible inyectado: " + combustible);
        Console.WriteLine("Potencia proporcionada: " + potencia);
        Console.WriteLine("Incremento de velocidad: " + incrementoVelocidad);
    }
}
¿Cuándo utilizar este patrón? Ejemplos reales
Este patrón es aconsejable, como ya hemos comentado, en situaciones en los que una misma operación (o conjunto de
operaciones) puedan realizarse de formas distintas. A grosso modo, el patrón Strategy realiza una tarea bastante similar
al patrón Template Method, salvo porque en este caso el algoritmo no tiene por qué contar con pasos en común y
porque Strategy confía en la composición mientras que Template Method se basa en la herencia.

Ejemplos reales de este patrón se aplican, por ejemplo, la serialización de objetos. Una interfaz que exponga un
método serialize() podrá codificar un objeto en distintos formatos (String64, XML, JSON). El cliente no necesita saber
cómo se realizará esta operación: bastará con que el contexto seleccione la estrategia adecuada y el resultado de la
operación dependerá de la opción concreta que se haya seleccionado.
Del mismo modo podemos pensar en una conexión a un servicio web: podremos realizarla mediante TCP/IP, HTTP,
HTTPS, Named Pipes… todo esto deberá ser transparente para el cliente: El contexto será el encargado de adoptar una
forma concreta de conexión.

¿Más ejemplos? Los compresores funcionan a través de estrategias (se utiliza un algoritmo distinto para comprimir en
zip o en rar), y en general, cualquier programa capaz de almacenar y transmitir datos en distintos formatos
implementarán este patrón. Por lo tanto, como podemos imaginar, nos encontramos, tanto por su utilidad como por su
sencillez, con uno de los patrones más utilizados de todos los expuestos por el GoF.
ID y Estrategia
LOS ROBOTS
Imaginemos que tenemos una clase llamada Robot, cada Robot puede
realizar una serie de operaciones fundamentales:
• Caminar
• Disparar
Desde luego hay muchas más pero esas serán suficientes para el
ejemplo.
Iniciemos con el análisis, en primera instancia revisemos la característica Disparar.
Si tenemos un conjunto de Robots donde todos ellos pueden disparar de manera
diferente podemos pensar en crear una clase base llamada Robot la cual desde luego
implementa la funcionalidad Disparar como virtual o abstract de tal forma que las
implementaciones concretas puedan establecer una forma particular de disparar en
cada caso.
Existen inicialmente 3 implementaciones de Robot
• RobotVigilante: Dispara como todos los Robot
• RobotMilitar: Dispara como todos los Robot
• RobotCasero: No dispara
Este es nuestro diagrama de clases:
public class Robot
{
public Robot()
{
}

public virtual void Disparar()


{
//Bang!
}
Este esquema funciona bien pero hay varios problemas que debemos afrontar si pensamos las cosas detenidamente.
• Cada vez que un Robot no dispare debemos sobrescribir el método virtual.
• Pueden requerirse Robots que disparen de manera diferente, en cuyo caso también se requiere sobrescribir el método virtual,
¿qué pasa con caminar? efectivamente pueden aparecer Robots que no caminen o Robots que lo hagan con un pie o con
cuatro pies.
Teniendo este escenario nos damos cuenta que el propósito inicial por el cual se ha utilizado la herencia se ha desvirtuado, pues
no es cierto que todos los Robot hagan las actividades de la misma forma, incluso pueden haber Robots que no hagan una
determinada actividad.
La herencia en este punto se nos ha convertido en un problema, ¿ya vieron cuál?, puede que no.
El problema es: MANTENIMIENTO, todos sabemos que crear un programa es solo la primera parte, la segunda parte es
mantener ese programa en el tiempo, hacerle mejoras, evolucionarlo etc.\ Y desde luego en el escenario de los Robots esto
también es una necesidad, necesitaremos crear nuevos Robots y modificar los existentes.
Pero al haber utilizado herencia nos encontraremos que algunas cosas habrá que cambiarlas en la clase base y otras en las clases
derivadas, peor aún puede haber un grupo de clases derivadas que no utilicen las funcionalidades de la clase base pero que
entre ellas si comparten la misma funcionalidad, esto es: tendremos código redundante.
El problema puede llegar a ser muy grueso.
LA SOLUCIÓN CLÁSICA
LA SOLUCIÓN CLÁSICA
Lo primero que a uno se le viene a la mente para resolver el tema de los Robot que no Disparan o
que no Caminan es utilizar interfaces, lo cual suele ser una muy buena idea, sobre todo teniendo
en cuenta este principio de diseño.
Programe contra una interfaz no contra implementaciones concretas.
En este sentido hay que ser claro que este principio hace referencia a interfaces desde el punto
de vista del diseño de software no de ningún lenguaje en particular y en este sentido entonces
una interfaz puede ser en esencia un Súper Tipo:
• Clase Base
• Clase Abstracta
• Interfaz
Podemos crear dos interfaces para identificar que habilidades tiene cada Robot.
• IDisparable
• ICaminable
*Sorry por los nombres, mi creatividad en ese sentido es limitada.
Esto nos permitirá tener Robots que Camine, Disparen, que no hagan nada o que solo hagan una
de las dos cosas.
public interface ICaminable{
void Caminar(); public class RobotVigilante : Robot, ICaminable, public void Disparar() {
IDisparable
} //Disparar Normal
{
}
public void Caminar() {
public interface Idisparable { }
//Caminar Normal
void Disparar();
}
} public class RobotCasero : Robot, ICaminable
{
public void Disparar() {
public class Robot public void Caminar() {
//Disparar Normal
{ //Caminar Normal
}
public Robot() { } }
}
}
public virtual void MatarAJohnConnor()
public class RobotMilitar : Robot, ICaminable,
{ IDisparable public class RobotDetectorDeJohnConnor : Robot,
IDisparable
//You could be miiine ♫♪ Yeaahh ♪♪♫ {
{
} public void Caminar() {
public void Disparar() {
} //Caminar Normal
//Disparar con sevicia hasta lograr objetivo
}
}
}
El tema de la complejidad... preocupante, pero más preocupante aún es el hecho que tenemos código redundante ya que aunque varios robots disparen de la misma
forma, cada uno tiene su propia implementación.
Así que estamos usando uno de los principios de diseño de software pero algo anda un poco mal, vamos a solucionarlo.
Para los más experimentados el indicio de solución salta a la vista: encapsulamiento.
Pero pongámoslo en el marco del diseño de software, aquí existe otro principio fundamental:
Identificar los aspectos que cambian, y sepáralos de los que se mantienen iguales.
Eso precisamente se hace en POO haciendo uso de encapsulamiento, cosa que los cambios en este objeto no afecten el resto del código de la implementación.
Encapsular, en este caso implica necesariamente crear un objeto nuevo por cada funcionalidad que cambia, las funcionalidades que cambian en nuestros Robot son
• Disparar
• Caminar
Estas funcionalidades que cambian las llamaremos en adelante comportamientos, behaviors en inglés. Es tiempo de extraer estos comportamientos en nuevos
objetos.
Cada acción ( caminar, disparar), tienen una serie de comportamientos posibles aunque exhiben la misma interfaz, es decir los mismos métodos con los mismos tipos
de datos, así que podemos pensar en generalizar dicha interfaz, de tal forma que podamos crear diferentes comportamientos, por ejemplo al caminar:
• CaminarNormal
• CaminarDeMedioLado
O al disparar
• DispararNormal
• DispararAmetralladora
Queda la duda de ¿Qué hacer con los que no caminan o no disparan? esta es la parte más bella
• NoCaminar
• NoDisparar
Este es el diagrama de clases de nuestros comportamientos, y abajo la implementación de los Robots
public interface IDispararBehavior public void Caminar() }
{ { }
void Disparar(); //Hacer como cangrejo
} }
public class DispararAmetralladora :
} IDispararBehavior
{
public interface ICaminarBehavior
{ public class NoCaminar : ICaminarBehavior
void Caminar(); { public void Disparar()
} {
//Disparar tacatacatacatacataca
public void Caminar()
}
public class CaminarNormal : ICaminarBehavior {
}
{ //nada
public void Caminar() }
{ } public class NoDisparar : IDispararBehavior
//Caminar normal {
}
public class DispararNormal : IDispararBehavior
}
{ public void Disparar()
{
public class CaminarDeMedioLado : //nada
ICaminarBehavior public void Disparar()
}
{ {
}
//Disparar normal
Este es el código de implementación de los robots haciendo uso de los
comportamientos creados.
public abstract class Robot public class RobotMilitar : Robot
{ {
protected IDispararBehavior _disparador; public RobotMilitar() {
protected ICaminarBehavior _caminador; _disparador = new DispararAmetralladora();
_caminador = new CaminarDeMedioLado();
public Robot() { } }
}
public void Caminar() { public class RobotCasero : Robot
_caminador.Caminar(); {
} public RobotCasero() {
_disparador = new NoDisparar();
public void Disparar() { _caminador = new CaminarNormal();
_disparador.Disparar(); }
} }

public virtual void MatarAJohnConnor() { public class RobotDetectorDeJohnConnor : Robot


//You could be miiine ♫♪ Yeaahh ♪♪♫ {
} public RobotDetectorDeJohnConnor() {
} _disparador = newDispararAmetralladora();
public class RobotVigilante : Robot _caminador = new NoCaminar();
{ }
public RobotVigilante() { }
_disparador = new DispararNormal();
_caminador = new CaminarNormal();
}
}
• Es una solución impecable, pero aún se puede hacer más! lo bueno
de tener separados los comportamientos es que nada impide que
podamos cambiar dichos comportamientos en tiempo de
ejecución... hell yeeaahh!
• Supongamos que queremos actualizar el Robot Detector De John
Connor para que ahora pueda caminar, como hacerlo? gracias a que
hemos programado contra interfaces y hemos encapsulado los
comportamientos que cambian, es algo muy sencillo de hacer.
Modificando la clase base, exponiendo de manera pública los
comportamientos:
public abstract class Robot Así expuestos podemos crear un objeto de cualquier tipo y modificar
{ eso en tiempo de ejecución!.
IDispararBehavior _disparador;
public IDispararBehavior Disparador {
get { return _disparador; } public static class Programa
set { _disparador = value; }
}
{
public static void Main()
ICaminarBehavior _caminador; {
public ICaminarBehavior Caminador { var connorKiller = new RobotDetectorDeJohnConnor();
get { return _caminador; }
set { _caminador = value; } connorKiller.MatarAJohnConnor();
} connorKiller.Caminador = new CaminarDeMedioLado();
public Robot() { }
Console.WriteLine("YEAH");
public void Caminar() { }
_caminador.Caminar(); }
}

public void Disparar() {


_disparador.Disparar(); Digamos que ahora se nos ocurre ponernos un poco mas
}
agresivos:
public virtual void MatarAJohnConnor() {
//You could be miiine ♫♪ Yeaahh ♪♪♫
}
}
public static class Programa En este último ejemplo hemos utilizado la clase RobotDetectorDeJohnConnor pero
observemos atentamente Qué pasa si en lugar de usar este Robot hacemos uso de la clase
{ base Robot ?
public class CaminadorAPropulsion : ICaminarBehavior Para ello solo debemos quitarle la marca abstract que fue puesta allí para nuestra
propuesta de solución inicial.
{ El resultado: se hace exactamente igual, es decir YA NO NECESITAMOS USAR
public void Caminar() HERENCIA!!!

{ public static class Programa


//Activar propulsores y demas {
} public class CaminadorAPropulsion : ICaminarBehavior
{
}
public void Caminar() {
//Activar propulsores y demas
public static void Main() }
{ }
var connorKiller = new RobotDetectorDeJohnConnor();
connorKiller.MatarAJohnConnor(); public static void Main()
connorKiller.Caminador = new CaminarDeMedioLado(); {
var connorKiller = new Robot();
connorKiller.MatarAJohnConnor();
//No es muy efectivo, provemos algo mejor
connorKiller.Caminador = new CaminarDeMedioLado();
connorKiller.Caminador = new CaminadorAPropulsion(); //No es muy efectivo, probemos algo mejor
connorKiller.MatarAJohnConnor(); connorKiller.Caminador = new CaminadorAPropulsion();
connorKiller.MatarAJohnConnor();
Console.WriteLine("YEEEEEEEEEEEEAHHHHHHHH");
} Console.WriteLine("YEEEEEEEEEEEEAHHHHHHHH");
} }
}
PATRONES DE COMPORTAMIENTO (V):
Objetivo:
PATRÓN STATE
“Permitir que un objeto modifique su comportamiento cuando su estado interno cambie. Parecerá que el objeto cambia de clase”.
• https://danielggarcia.wordpress.com/2014/05/20/patrones-de-
comportamiento-v-patron-state/

También podría gustarte