Está en la página 1de 119

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;
        v.DireccionAsistida = true;
constructor, codificaremos una clase A3SportbackBuilder que herede     }
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";

llantas de 15cm estándar,         v.Modelo = "Xsara Picasso";


    }
    //
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";


    }

implemente de una forma distinta     public


    {
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()
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 DECORATOR

También podría gustarte