GoF – Patrones de diseño (XII): Facade

El siguiente patrón estructural que vamos a ver es el patrón Facade, que básicamente nos ayuda a crear o nos provee de una interfaz unificada para manejar un conjunto de objetos en un subsistema. De está forma, estaremos definiendo un interfaz de alto nivel que hará los subsistemas más fáciles de manejar. Por hacer una referencia vinculada a la literatura fantástica, sería algo así como “uno para dominarlos a todos” (ESDLA).

La estructuración de un sistema en pequeños subsistemas permite reducir la complejidad de dicho sistema, el problema es que muchas veces crea muchas dependencias entre los subsistemas implementados. Es en este caso donde el patrón Facade nos puede ayudar creando una única interfaz simple que nos permita acceder a las funcionalidades de nuestros subsistemas. De esta forma, los clientes que utilicen nuestro sistema no necesitarán conocer nuestros diferentes subsistemas y su funcionamiento, sino que solo necesitaran conocer el interfaz para manejar el sistema completo.

El patrón Facade se puede aplicar:

  • Cuando se quiere proveer de una interfaz simple para un conjunto complejo de subsistemas. Por ejemplo, la aplicación de muchos patrones de diseño provoca la creación de muchas clases muy pequeñas y reutilizables, pero este nivel de granuralidad hace difícil el manejo del sistema, aquí podríamos aplicar este patrón.
  • Cuando hay muchas dependencias entre los clientes y el sistema. Aplicando el patrón podemos aumentar el nivel de desacoplamiento aumentando así la independencia y la portabilidad.
  • Cuando quieres introducir capas en tus subsistemas, usando el patrón para definir un punto de entrada. Además, si los subsistemas son muy dependientes, podemos simplificar esta dependencia haciendo que estos se comuniquen a través de sus Facades.

Los elementos que componene este patrón son:

  • Facade: Conoce los subsistemas implicados en el sistema global, accede a ellos y les envía las peticiones de los clientes.
  • Subsystem classes: Implementan la funcionalidad del sistema, realizan las tareas enviadas por el Facade y no tienen referencias a Facade.

Con todo esto, las consecuencias de la aplicación de este patrón son una reducción del número de objetos que tienen que manejar los clientes ya que, en vez de necesitar un objeto por cada subsistema implicado, solo necesitan el objeto Facade. Esto último provoca un acoplamiento más débil entre el sistema y los clientes, con lo cual hace más fácil los cambios o modificaciones en el sistema y sus subsistemas, permitiendonos también menos acoplamiento entre nuestros subsistemas mejorando las dependecias de compilación, cosa muy importante en grandes sistemas. Aunque, la implementación del patrón no impide, en caso de necesitarlo, que algún cliente use o acceda a alguno de nuestros subsistemas.

Pero como siempre, aunque el punto de vista teórico está muy bien y es muy importante, lo mejor es verlo con un pequeño ejemplo para que nos quede del todo claro. En este caso, vamos a coger un sistema simple de dibujo de figuras geométricas.

Subsystem classes:

public class Circle {
    public void draw() {
        ...
    }
}

public class Square {
    public void draw() {
        ...
    }
}

public class Rectangle {
    public void draw() {
        ...
    }
}

Facade:

public class ShapeProducer() {
    private Circle circle;
    private Square square;
    private Rectangle resctangle;

    public void drawCircle() {
        circle = new Circle();
        circle.draw();
    }

    public void drawSquare() {
        square = new Square();
        square.draw();
    }

    public void drawRectangle() {
        rectangle = new Rectangle();
        rectangle.draw();
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        ShapeProducer sp = new ShapeProducer();
        sp.drawCircle();
        sp.drawSquare();
        sp.drawRectangle();
    }
}

Como vemos, si no tuviéramos el objeto Facade, el cliente tendría que conocer y tener definidos los tres objetos de nuestro subsistema, de esta forma, solo necesita nuestro objeto Facade.

Otros patrones realcionados con este son: Abstract Factory, que puede ser utilizado junto con Facade. Mediator, no visto aún, similar a Facade en el aspecto de abstraer funcionalidad, pero realizando otro enfoque. Y está indirectamente relacionado con Singleton, ya que muchas veces el objeto Facade es Singleton también.

Bueno, hasta aquí por hoy. Nos vemos.

GoF – Patrones de diseño (XII): Facade

GoF – Patrones de diseño (XI): Decorator

El siguiente patrón de diseño que vamos a ver es el patrón Decorator. Dicho patrón nos permitirá añadir funcionalidades o responsabilidades a un objeto de forma dinámica. Este patrón nos provee de una alternativa muy flexible a la creación de subclases para extender funcionalidades. Esto nos permitirá, en tiempo de ejecución, añadir esta funcionalidad o responsabilidad extra que necesita nuestro objeto. esto se podría hacer a través de la herencia pero no sería lo suficientemente flexible ya que de esta forma serían añadidas de forma estática. En vez de esto, nuestro objeto decorator rodeará al objeto inicial añadiendo estás responsabilidades o funcionalidades. Se hace referencia muchas veces a este patrón como Wrapper. Estoy seguro que este nombre si que lo habréis escuchado muchas veces con anterioridad.

Este patrón lo podemos aplicar para:

  • Añadir responsabilidades a un objeto individual de forma dinámica y transparente sin afectar a otros objetos.
  • Responsabilidades que pueden ser eliminadas de un objeto.
  • Cuando la extensión a través de la herencia no es viable. Por ejemplo, cuando esto provocaría una gran cantidad de subclases o la definición de la clase padre está oculta o no es accesible para realizar esta herencia.

Los elementos implicados en este patrón son:

  • Component: Define la interfaz de los objetos a los que se le podrá añadir responsabilidades dinámicamente.
  • ConcreteComponent: Define el objeto al que se le podrán añadir responsabilidades.
  • Decorator: Mantiene una referencia al objeto Component y define una interfaz que se ajusta a la interfaz de Component.
  • ConcreteDecorator: Añade las responsabilidades al componente.

El uso de este patrón, como ya hemos comentado anteriormente, nos añade mucha más flexibilidad que la herencia estática proveyéndonos de mecanismos para añadir o eliminar responsabilidades en tiempo de ejecución. Quizás el mayor problema que plantea será el de mantenibilidad del código ya que genera muchos objetos pequeños muy similares.

Pero, como siempre, lo mejor de todo es ver esto con un ejemplo. En este caso consistirá en un sistema de envío de emails corporativos.

Component:

public interface IEmail {
    public String getContents();
}

ConcreteComponent:

public class Email implements IEmail {
    private String content;

    public Email(String content) {
        this.content = content;
    }

    @Override
    public String getContents() {
        return content;
    }
}

Decorator;

public abstract class EmailDecorator implements IEmail
    IEmail originalEmail;
}

ConcreteDecorator:

public class ExternalEmailDecorator extends EmailDecorator {
    private String content;

    public ExternalEmailDecorator(IEmail basicEmail) {
        originalEmail = basicEmail;
    }

    @Override
    public String getContents() {
        content = addDisclaimer(originalEmail.getContents());
        return content;
    }

    private String addDisclaimer(String message) {
        return  message + "\n Disclaimer";
    }
}

public class SecureEmailDecorator extends EmailDecorator {
    private String content;

    public SecureEmailDecorator(IEmail basicEmail) {
        originalEmail = basicEmail;
    }

    @Override
    public String getContents() {
        content = encrypt(originalEmail.getContents());
        return content;
    }

    private String encrypt(String message) {
        return encryptedMessage;
    }
}

Main:

public class Sender() {
    public static void main(String[] args) {
        ...
    }

    public String generateEmail(IEmail email, int sentType) {
        String emailText = "";

        switch(sentType) {
            case EXTERNAL:
                EmailDecarator d1 = new ExternalEmailDecorator(email);
                emailText = d1.getContents();
                break;
            case SECURE:
                EmailDecarator d2 = new SecureEmailDecorator(email);
                emailText = d2.getContents();
                break;
            default:
                ...
        }

        return emailText;
    }
}

Como podemos ver en el ejemplo se modifican de forma fácil los emails que queremos enviar.

Otros patrones relacionados con este son: Adapter, aunque similares, se diferencian en que el Decorator modifica solo las responsabilidades del objeto, mientras que el Adapter modifica la interfaz. El Composite, ya que se puede ver al patrón Decorator como una degeneración de este con un solo componente. Strategy, es otra alternativa de cambiar un objeto.

Bueno, hasta aquí hemos llegado por hoy. Nos vemos.

GoF – Patrones de diseño (XI): Decorator

GoF – Patrones de diseño (X): Composite

Tras un breve (quizás no tan breve) periodo de tiempo, vamos a continuar con la serie de artículos relacionados con los patrones de diseño. El siguiente patrón que vamos a ver es el patrón “Composite”. El objetivo de este patrón es el de montar los objetos en una estructura de árbol para representarlos de una forma jerarquizada. De este modo, se podrán manejar de forma similar y uniforme, tanto los objetos individuales como los objetos compuestos.

Este patrón es aplicable en situaciones es las que se necesita trabajar simultaneamente con elementos simples y colecciones que contienen elementos simples u otras colecciones, obteniendo de esta forma la estructura de árbol comentada. Un ejemplo muy utilizado para hacer ver la necesidad y aplicabilidad de este patrón es la implementación de un editor gráfico en el que podemos encontrar multitud de figuras y, además, escenas compuestas por muchas figuras. Siendo las figuras los objectos simples y las escenas colecciones de objetos simples u otras escenas.

Este patrón lo podemos aplicar en las siguientes situaciones:

  • Representar jerarquias de objetos simples y compuestos que puedan ser manejados de forma uniforme.
  • Permitir a los clientes ignorar las diferencias entre objetos individuales o composiciones de objetos.

Los elementos implicados en este patrón son:

  • Component: Declara la interfaz para objectos de la composición, implementa el comportamiento por defecto que será común a todas las clases, declara la instancia para el acceso y manejo de los componentes hijos y, opcionalmente, define la interfaz para acceder a los componentes padres en una estructura recursiva e implementa esta última si es necesario.
  • Leaf: Representa los objetos simples de la composición. Estos objetos no tiene más hojas. Además, define el comportameinto de estos objetos primitivos.
  • Composite: Define el comportamiento para componentes que tienen hijos, almacena objetos simples de la composición e implementa el comportamiento relacionado con los hijos en el “Component”.
  • Client: Manipula los objetos de la composición a través de los métodos del “Component”.

Como en todos los casos anteriores, la aplicación del patrón tiene sus fortalezas, pero también provoca algunos pequeñas pegas como que puede hacer el diseño sea demasiado general y, en ocasiones, que sea díficil controlas los elementos que se incluyen en las diferentes composiciones y pertenecen a ellas. Para paliar este problema, se pueden incluir controles en tiempo de ejecución para poder controlarlo.

Pero, para ver de verdad como funciona esto, vamos a realizar un pequeña implementación como siempre. El típico ejemplo, como ya he comentado antes, suele ser algún editor gráfico, pero para nuestro ejemeplo vamos a utilizar algo que está en la naturaleza y que posee está estructura de árbol que perseguimos implementar, las moléculas. Como objetos simples, tendremos los átomos, y como objetos compuestos las moléculas, que a su vez pueden estar compuestas por otras moléculas.

Component:

public abstract class Component {
    protected String nombre;
    protected int weight;
    public Component(String nombre, int weight) {
        ...
    }
    abstract public void add(Component c);
    abstract public void remove(Component c);
    abstract public int obtainWeight();
}

Leaf:

public class Atom extends Component {
    public Atom(String nombre, int weight) {
        super(nombre, weight);
        ...
    }
    public void add(Component c) {
        ...
    }
    public void remove(Component c) {
        ...
    }
    public int obtainWeight() {
        return weight;
    }
}

Composite:

public class Molecule extends Component {
    private List<Component> list;
    public Molecule(String nombre) {
        this.nombre = nombre;
        ...
    }
    public void add(Component c) {
        list.add(c);
    }
    public void remove(Component c) {
        list.add(c);
    }
    public int obtainWeight() {
        int total = 0;
        for(Component c : list) {
            total += c.obtainWeight();
        }
        return total;
    }
}

Client:

public class Laboratory {
    public static void main(String[] args) {
        Component a1 = new Atom("a1", 12);
        Component a2 = new Atom("a2", 10);
        Component m1 = new Molecule("m1");
        m1.add(a1);
        m1.add(a2);
        System.out.println(a1.obtainWeight());
        System.out.println(a2.obtainWeight());
        System.out.println(m1.obtainWeight());
    }
}

Con este código en el cliente, estaríamos creando dos nuevos átomos y con ellos formando una molécula y utilizando sus métodos para obtener su peso molecular o atómico segun corresponda.

Otros patrones relacionados con este son: el patrón Decorator que muchas veces se suele utilizar en conjunto con Composite teniendo de esta forma una clase común padre. El patrón Flyweight, que aún no hemos visto, pero permite compartir componentes, aunque se pierde la accesibilidad a los componentes padres. El Iterator, tampoco lo hemos visto aún, puede ser usado para cruzar objetos Composite. El patrón Visitor, tampoco lo hemos visto aún, localiza operaciones y componentes que podrían de otra forma distribuirse por las clases Composite y Leaf.

Nos vemos.

GoF – Patrones de diseño (X): Composite

GoF – Patrones de diseño (IX): Bridge

El siguiente de los patrones que vamos a ver es el Bridge. El objetivo de este patrón es la separación (desacoplamiento) de una abstracción de su implementación, de tal forma que ambas puedan ser modificadas independientemente sin a fectar la una a la otra. Bien, ¿y qué significa esto? Porque seguro que os lo estáis preguntando o al menos, yo si que lo hice la primera (segunda y tercera) vez que leí la frase. Por ponerlo en palabras más entendible o intentar explicar la idea, vamos a comentar primero el caso habitual. Imaginemos una clase abstracta a partir de la cual, posteriormente, vamos a implementar por mecanismos de herencia varia subclases. En este caso, tanto la clase abstracta (que está definiendo el interfaz), como las subclases implementadas, están fuertemente ligadas lo que nos hace perder mucha flexibilidad a la hora de modificar, extender o reusar todo este conjunto. Pues bien, este problema de flexibilidad es lo que viene a solicitar este patrón Bridge colocando en diferentes jerarquias la clase abstracta y sus implementaciones.

Utilizamos este patrón cuando:

  • Se quiere evitar un enlace permanente entre la abstracción y su implementación. Este podría ser el caso, por ejemplo, cuando una implementación debe ser seleccionada o cambiada en tiempo de ejecución.
  • Cuando la abstracción y su implementación deben poderse extender creando nuevas subclases. En este caso, el patrón nos permite combinar diferentes abstracciones e implementaciones y extender todas ellas de forma independiente.
  • Los cambios en la implementación de una abstracción no deberían tener impacto en los clientes (el código no debería tener que ser recompilado).
  • Los cambios en la implementación no deberían ser visibles para los clientes.
  • Cuando se quiere compartir una implementación entre múltiples clientes, pero no se desea que el cliente sea conciente de esto.

Los elementos implicados en este patrón son:

  • Abstraction: Define la clase abstracta que será la interfaz y mantiene la referencia al objeto de tipo Implementor.
  • RefinedAbstraction: Extiende la intefaz definida por Abstraction.
  • Implementator: Define la interfaz para la implementación de las clases. No tiene porque tener correspondencia con el interfaz Abstraction. De hecho, suelen ser diferentes. Por lo general, Implementor facilita las operaciones primitivas,y Abstraction define las operaciones de alto nivel basadas en esas primitivas.
  • ConcreteImplementor: Implementa Implementor creando ya una clase para su utilización.

Las consequencias de la aplicación de este patrón son el desacoplamiento de la interfaz y de su implementación, pudiendo cambiar estos incluso en tiempo de ejecución. Además, se eliminan dependencias de compilación y se consigue una arquitectura estructurada en más niveles (esto, no se si es del todo bueno, pero…) Otra de las cosas que si que nos aporta es la flexibilidad ya que se puede heredar de una u otra pudiendo hacer diferentes jerarquias. Y finalmente, nos aporta el esconder detalles de implementación a los clientes.

Pero como siempre, vamos a ver un poco en código como queda esto, que yo sigo pensando que es una de las mejores formas de entender finalmente la idea. Vamos unos mandos a distancia de televisión.

Implementator:

public interface TV {
    public void on();
    public void off();
    public void tunechannel(int);
}

Clase interfaz para las diferentes marcas de televisores.

ConcreteImplementator:

public class Sony implements TV {
    public void on() { ... }
    public void off() { ... }
    public void tuneChannel(int channel) { ... }
}

ConcreteImplementator:

public class LG implements TV {
    public void on() { ... }
    public void off() { ... }
    public void tuneChannel(int channel) { ... }
}

Estos serán nuestros modelos especificos de televisiones.

Abstraction:

public abstract class RemoteControl {
    private TV tv;
    public void on() { tv.on(); }
    public void off() { tv.off(); }
    public void tuneChannel(int channel) { tv.tuneChannel(channel); }
}

Con esto tendríamos definido nuestro control remoto.

RefinedAbstraction:

public class RemoteControlPlus implements RemoteControl {
    private int channel;
    public void next() { channel++; }
    public void previous() { channel--; }
}

Con esto le hemos añadido a nuestor control remoto más funcionalidades sin tener que modificar nada más en la jerarquia de clases, ni haber modificado nada en el Implementator. Esto, como ya se ha dicho antes, nos aporta más flexibilidad, pero genera más complejidad y niveles en nuestra estructura jerarquica lo cual no siempre es bueno. Pero bueno, como siempre, hay que ponderar todas las decisiones que tomemos y ver si nos aportan más beneficios o más problemas.

Otros patrones relacionados con este son el de Abstract Factory que puede crear y configurar un Bridge particular, y el patrón Adapter que sele ser muy util para hacer que clases no relacionadas trabajen juntas.

Hasta aquí todo por hoy. Nos vemos.

GoF – Patrones de diseño (IX): Bridge

GoF – Patrones de diseño (VIII): Adapter

Retomando de nuevo la serie de artículos sobre patrones de diseño, hoy vamos a ver el patrón Adapter. Este va a ser el primero de los patrones estructurales que vamos a ver. La definición dada por el libro es que este patrón nos permite convertir una interfaz de una clase en otra interfaz que el cliente está esperando. El patrón Adapter permite de esta forma trabajar juntas a clases que de otra forma no podrían por la incompatibilidad de sus interfaces. Básicamente, y en palabras mucho más llanas, vosotros lo conoceréis como Wrapper, que no es más que una envoltura sobre algún objeto en concreto para que podamos utilizarlo desde puntos donde no estaba pensado antes.

Con las lineas que se han explicado arriba deberíamos tenerlo ya claro, sobre todo, después de saber que este patrón es un wrapper, termino que casi cualquier desarrollador estoy seguro de que conoce. Pero de todas formas, vamos a entrar un poco en detalle. Este tipo de patrón se creo para intentar que objetos implementados a partir de diferentes interfaces pudieran trabajar juntos salvando esta diferencia de interfaces. De esta forma objetos que ya tenemos implementeados pueden ser adaptados para ser reutilizados sin que se necesiten cambios en ellos, simplemente envolviéndolos con una capa alrededor que nos permitirá adaptarlos al nuevo interfaz deseado. Pero como siempre, lo mas fácil es ver esto con un ejemplo, así que sigamos avanzando.

Este patrón se compone de los siguientes elementos:

  • Target: Define el dominio específico de la interfaz que el cliente va a utilizar.
  • Client: Maneja los diferentes objetos según le permite el interfaz Target.
  • Adaptee: Define un interfaz existente que necesita ser adaptado.
  • Adapter: Adapta el interfaz de Adaptee al interfaz usado por el cliente Target.

Al final, el comportamiento resimido de esto, será que el cliente llamará a métodos del interfaz Adapter que a su vez llamarán a métodos del objeto Adaptee.

Pero bueno, vamos a ver todo esto con un poco de código que seguro que nos lo deja algo más claro que una explicación. Vamos a implementar una mini aplicación que poner vehiculos de carreras a correr en un similador por ejemplo, y añadir un vehiculo que no es de carreras para hacer unas pruebas.

Target:

public interface VehiculoCarreras {
    public void correr();
    ...
}

Clases válidas:

public class CitroenCarreras extends vehiculoCarreras {
    public void correr() {
        ...
    }
}
public class OpelCarreras extends vehiculoCarreras {
    public void correr() {
        ...
    }
}

Adaptee:

public class Renault {
    public void arranca() {
        ...
    }
    public void meterPrimera() {
        ...
    }
    public void acelerar() {
        ...
    }
    ...
}

Adapter:

public class RenaultCarrerasWrapper extends VehiculoCarreras {
    public void correr() {
        ...
        renault.arranca();
        renault.metePrimera();
        renault.acelera();
        ...
    }
}

Client:

public class Main() {
    public static void main(String[] args) {
        VehiculoCarreras vc = new CitroenCarreras();
        vc.correr();

        vc = new OpelCarreras();
        vc.correr();

        // vc = new Renault(); No es posible hacer esto
        vc = new RenaultCarrerasWrapper();
        vc.correr();
    }
}

Como podéis ver tenemos entre nuestros vehiculos de carreras un coche normal (Renault) porque queremos hacer una prueba con él, para no tener que tocar la implementación de este, hemos desarrollado un wrapper por encima (RenaultCarrerasWrapper) para que pueda ser manejado por nuestro programa.

Así de simple es este patrón. Como final, solo queda añadir que está relacionado con patrones como:

  • Bridge: Tienen una estructura similar, pero el objetivo de Bridge es separar la interfaz de la implementación. Ya lo veremos próximamente.
  • Decorator: Es otro camino para cambiar un objeto sin cambiar su interfaz, quizás este sea un poquito más transparente, lo cual le permite soportar composición recursiva, cosa que no es posible con Adapter.
  • Proxy: Define una representación o sustituto de un objeto sin cambiar su interfaz. Ya lo veremos más adelante.

Bueno, hasta aquí todo. Espero que os sirva de ayuda y haberos dejado un poquito más claro este patrón. Nos vemos.

GoF – Patrones de diseño (VIII): Adapter

GoF – Patrones de diseño (VII): Singleton

El siguiente de los patrones que vamos a ver es el de Singleton. Asumo que muchos de vosotros ya lo conoceréis ya que es muy común y muchas clases Java lo implementan, pero había que explicarlo también.

El objetivo de este patrón es asegurarse de que de una clase solo existe una instancia y que esta es accesible, o mejor dicho, ofrecer un punto de acceso a ella.

Existen muchas clases para las cuales es importante tener únicamente una sola instancia que pueda ser utilizada en muchas partes diferentes del sistema. Por ejemplo, por muchas impresoras que haya en nuestro sistema lo interesante es tener una sola cola de impresión que maneje todas las impresiones. Otro ejemplo podría ser un gestor de ventanas de una aplicación, ya que no vamos a tener varios gestores de ventanas para una misma aplicación. Y sin duda, una que todo programador de Java conocerá, la clase Calendar que es un objeto que implementa el patrón Singleton. Si no lo sabías aún, terminad de leer el artículo y os daréis cuenta fácilmente de ello.

Vamos a empezar. Para ello mantengamos dos ideas en la cabeza: tener una sola instancia y que sea accesible desde cualquier parte de nuestra aplicación.

Alguno estará pensando que teniendo variables globales, ¿para qué hace falta este patrón? Pero pensemos que esto hace un objeto accesible desde cualquier lado, pero no nos asegura la existencia de una sola instancia ya que se pueden crear nuevas instancias. El crearlas o no, quedaría en manos de los desarrolladores, lo cual sabemos que es una buena idea siempre.

Algunos de los beneficios que nos aporta el patrón son:

  • Poder controlar el acceso a la instancia.
  • Reduce el espacio de nombres ya que evita contaminarlo con variables globales.
  • Permite refinar operaciones y la representación a través de la creación de subclases.
  • Permite controlar fácilmente y sin apenas cambios el número de instancias que creamos. Sé que el patrón está enfocado a tener una sola instancia, pero en determinadas circunstancias quizás necesitamos dos o tres por ejemplo.

Todo esto está muy bien, pero vamos a ver un poco de código, porque este patrón es tan simple que con un simple vistazo al código lo entenderemos muy fácilmente.

Clase que implementa patrón Singleton:

public class PrintSpooler {
    private static PrintSpooler instance = null;
    protected PrintSpooler() {
        …
    }
    public static PrintSpooler getInstance() {
        if (instance == null) {
            instance = new PrintSpooler();
        }
        return instance;
    }
}

Main:

public class Main {
    public static void main(String[] args) {
        PrintSpooler spooler = PrintSpooler.getInstance();
        …
    }
}

Como podéis ver el constructor del objeto no es accesible y el el método “getInstance” el que gestiona si se ha de crear o no una instancia del objeto, de forma que si ya existe devuelve la instancia existente.

¿Veis ahora la similitud con la clase Calendar de Java?

Hasta aquí hemos llegado con los patrones creacionales. A partir de aquí, en sucesivos artículos empezaremos a ver los patrones estructurales. Nos vemos.

GoF – Patrones de diseño (VII): Singleton

GoF – Patrones de diseño (VI): Prototype

El siguiente de los patrones que vamos a ver es el patrón Ptototype que pertenece, al igual que los anteriores, al grupo de patrones creacionales.

Este patrón tiene como objetivo la especificación de un tipo de objeto que será un prototipo para la creación de nuevos objetos copiando este, o mejor dicho, clonando este prototipo.

Una explicación más informal de estoy sería algo así como, construir una jerarquía de clases en las cuales, el primer objeto que se crea sea el prototipo, y a partir de este momento, no se van a crear más nuevos objetos, sino que se van a clonar estos a partir del primero. Por aproximarlo un poco a la programación, aunque luego veremos un ejemplo, nuestra aplicación hará un “new” del objeto prototipo y a partir de ahí, el esto de objetos se obtendrán por clonación.

Y esto, ¿para que sirve? Pues por un lado, viene a solventar problemas derivados de clases dependientes de factores externos que solo se conocerán en tiempo de ejecución y, por otro, nos permite evitar, en el caso de objetos muy complejos, los problemas en la creación de estos.

Se debería usar este patrón cuando el sistema debería ser independiente de cómo sus productos son creados, rellenados y presentados. Además, como ya he comentado, cuando la clase a instanciar se especifica en tiempo de ejecución o para evitar la creación de factorías con herencias de clases complejas o cuando las instancias de una clases difieren únicamente en un estado. En este último caso suele ser mejor, crear el prototipo y clonar dicho prototipo para obtener instancias de nuevos objetos.

Este patrón se compone de los siguientes elementos:

  • Prototype: Declara una interfaz para clonarse.
  • ConcretePrototype: Implementa la operación de clonación para si mismo.
  • Client: Crea un nuevo objeto, pidiendo al prototype que se clone.

Aunque ya hemos adelantado una cuantas, las consecuencias de la utilización de este patrón son las siguiente:

  1. Nos permitirá crear o borrar productos en tiempo de ejecución.
  2. La especificación de objetos nuevos variando sus valores.
  3. La especificación de objetos nuevos variando su estructura.
  4. Reduce el número de subclases respecto al resultado si no utilizáramos este patrón o si utilizáramos otros como Factory Method para los casos que cubre Prototype.
  5. Nos permite la configuración de una aplicación con clases dinámicas.

La única consideración importante que tenemos que tener, ya sabéis un “Must to Have” es que tenemos que implementar la operación de clonación en cada una de las clases que se van a generar a partir del prototipo. Solo con esto ya podemos realizar la implementación de nuestro patrón.

Peor bueno, ya para no aburriros más, vamos a pasar a un ejemplo de implementación, que al fin y al cabo es lo más divertido. Como siempre, el ejemplo va a ser en Java que, en este caso, nos aporta la interfaz Clonable en su API. Para el que no la conozca, le invito a echarle una ojeada, pero básicamente es un interfaz que nos ofrece Java para realizar una implementación rápida y fácil de este patrón. Esto nos da un ejemplo de lo extendido que está.

El caso más fácil a exponer, y que deliberadamente lo voy a exagerar un poco más para que veáis la utilidad del patrón, es la creación de objetos personas. En este caso concreto vamos a hacer una mini aplicación donde crearemos dos personas que serán hermanos para trabajar con ellos.

Prototype:

Será la clase ofrecida por el API de Java Clonable, con lo cual no la tendremos que implementar

ConcretePrototype:

public class Persona implements Comparable {
    /* Datos personales: Nombre, primer apellido, segundo apellido,
       nombrePadre, nombreMadre, teléfonoDomicilio, nacionalidad,
       calle, numero, ciudad, códigoPostal,… */
    /* Getters y Setters */
}

Client:

public class Main {
    public static void main(String[] args) {
        Persona juan = new Persona();
        /* llamada a setters (mínimo 11 para nuestro caso*/
        Persona maria = (Persona)juan.clone();
        /* Cambiar nombre */
        maria.setNombre(“Maria”);
        /* Trabajar con los objetos */
    }
}

Como se puede ver, la operación clone nos ha ahorrado un montón de setters, y esto hablado de un objeto muy simple. Ahora imaginad uno compuesto por objetos complejos o multitud de campos.

Bueno, hasta aquí hemos llegado por hoy. Nos vemos.

GoF – Patrones de diseño (VI): Prototype

GoF – Patrones de diseño (V): Factory Method

El siguiente de los patrones que vamos a revisar es el de “Factory Method”. En este caso, como podéis ver, el nombre es bastante similar a uno de los patrones ya vistos en esta serie de artículos, este sería el “Abstract Factory”. A parte del nombre, existen entre ambos patrones varias similitudes más, de hecho, se puede considerar que el patrón “Factor Method” es una simplificación del patrón de “Abstract Factory”. En mi caso concreto, hasta empezar a leer el libro, no hacía ninguna distinción entre uno y otro, para mi eran algo así como: una factoría compleja (Abstract Factory), y una factoría simple (Factory Method). Y es aquí donde vemos un nuevo ejemplo de la importancia en muchas ocasiones de saber como llamar  de forma correcta aquello que sabemos.

Sin más rodeos, vamos a empezar.

El patrón “Factory Method” se define como una interfaz para la creación de cierto tipo de objeto, permitiendo que las subclases decidan que clase concreta necesitan instanciar. El problema que se plantea en algunos entornos es que una clase no puede anticipar el tipo de objetos que debe crear debido a la jerarquía de clases existente, lo cual provoca que tenga que delegar esta tarea en una subclase.

Por decir lo de una forma menos intrincada, viene a solucionar el problema que se presenta cuando tenemos que crear la instancia de un objeto pero a priori no sabemos aún que tipo de objeto tiene que ser, generalmente, porque depende de alguna opción que seleccione el usuario en la aplicación o porque depende de una configuración que se hace en tiempo de despliegue de la aplicación.

Este patrón se compone de:

  • Product: Define la interfaz de los objetos que de van a crear.
  • ConcreteProduct: Implementación de la interfaz.
  • Creator: Declara la factoría y devuelve un objeto del tipo producto. Además, puede definir una implementación por defecto para la factoria que devolvería un objeto ConcreteProduct por defecto.
  • ConcreteCreator: Sobreescribe el método de la factoría para devolver una instancia concreta de un objeto ConcreteProduct.

A la hora de la implementación tenemos varias opciones disponibles:

  1. El Creator es una clase abstracta y no ofrece ningún tipo de implementación para la factoría que declara. (Ejemplo 1)
  2. El Creator es una clase concreta y ofrece una implementación por defecto de la factoría.
  3. La parametrización de la factoría. Donde la factoría recibe un parámetro con el tipo de objeto que tiene que crear. Todos los objetos disponibles tiene que compartir la interfaz Product. (Ejemplo 2)

No teniendo mucho más que describir, vamos a pasar al ejemplo, donde yo creo que entenderemos mejor todo esto. Como tenemos varias formas posibles de implementación y este yo creo que, junto con el patrón Singleton (que ya veremos), es uno de los patrones que más se utilizan en Frameworks y desarrollos, vamos a ver dos ejemplos. El primero de los tipos vistos más arriba y el parametrizado.

Ejemplo 1: Clase abstracta sin implementación por defecto.

Creator:

public abstract class DBManager {
    public abstract DB factoryMethod();
}

ConcreteCreator:

public class MySQLDBManager extends DBManager {
    protected DB factoryMethod() {
        return new MySQLDB();
    }
}
public class OracleDBManager extends DBManager {
    protected DB factoryMethod() {
        return new OracleDB();
    }
}

Product:

public interface DB {
    public void operation();
}

ConcreteProduct:

public class MySQLDB implements DB {
    public void operation() {
        System.out.println(“Soy MySQL”);
    }
}
public class OracleDB implements DB {
    public void operation() {
        System.out.println(“Soy Oracle”);
    }
}

Main:

public class Main {
    public static void main(String[] args) {
        DBManager manager = new MySQLDBManager();
        MySQLDB mysql = manager.factoryMethod();
        mysql.operation();
        manager = new OracleBDManager();
        OracleDB oracle = manager.factoryMethod();
        oracle.operation();
    }
}

Ejemplo 2: Factoría parametrizada.

Creator and ConcreteCreator:

public class DBManager {
    public static DB createDBConnection(String descriptor) {
        if (“Oracle”.equals(descriptor)) {
            return OracleDB();
        } else if (“MySQL”.equals(descriptor)) {
            return MySQLDB();
        } else { … }
    }
}

Product:

public interface DB {
    public void operation();
}

ConcreteProduct:

public class MySQLDB implements DB {
    public void operation(){
        System.out.println(“Soy MySQL”);
    }
}
public class OracleDB implements DB {
    public void operation(){
        System.out.println(“Soy Oracle”);
    }
}

Main:

public class Main {
    public static void main(String[] args) {
        DB dataBase = DBManager. createDBConnection(“MySQL”);
        dataBase.operation();
        dataBase = DBManager. createDBConnection(“Oracle”);
        dataBase.operation();
    }
}

Ya tenemos una más. Espero que hasta aquí esté siendo todo claro. Dentro de poco la siguiente entrega. Nos vemos.

GoF – Patrones de diseño (V): Factory Method

GoF – Patrones de diseño (IV): Builder

El siguiente patrón que vamos a ver es el patrón “Builder”. Como resumen y a modo de idea con la que nos podemos quedar en la cabeza antes de entrar en materia, este patrón consiste en hacer una separación de la construcción de objetos complejos o compuestos de su representación de modo que el mismo proceso de construcción pueda crear diferentes representaciones.

Principalmente se usa para evitar situaciones de acoplamiento. Para el que no esté familiarizado con este término, el acoplamiento define el nivel de dependencia entre clases y como buena práctica de desarrollo siempre se tiende a intentar alcanzar un nivel bajo de acoplamiento si es posible. El nivel más bajo de acoplamiento es cuando dos clases pueden funcionar una sin la otra de forma independiente. El nivel más alto, es cuando una clase no puede funcionar sin la otra, por ejemplo, cuando una clase necesita acceder a un dato contenido en la otra. Como nos estamos yendo un poquito por las ramas, si no tenéis suficiente con lo descrito aquí os recomiendo que busquéis sobre factores que permiten mejorar la programación como: acoplamiento, modularidad, cohesión…

Siguiendo con el patrón, además de la reducción del acoplamiento en nuestro sistema, persigue que tengamos diferentes representaciones de un objeto construido. Sé que todo este tema suena un poco abstracto y difícil de entender inicialmente, pero creo que más abajo con el ejemplo quedará más claro.

Este patrón de se compone de:

  • Builder: Especifica la interfaz abstracta para crear las partes de un objeto Product.
  • ConcreteBuilder: Construye y monta las partes de un producto a través de la implementación de la interfaz Builder, define y mantiene el registro de la representación que se crea y proporciona una interfaz para recuperar el Producto.
  • Director: Construye el objeto usando la interfaz Builder
  • Product: Representa al objeto complejo en construcción. El ConcreteBuilder construye la representación interna del producto y define el proceso con el que será montado. Además, incluye las clases que definen las partes que constituyen el objeto (no olvidemos que es un objeto complejo) incluyendo las interfaces para montar el resultado final.

Al final los pasos para la correcta utilización del patrón son los siguientes:

  1. El Cliente crea un objeto Director y lo configura con el objeto Builder.
  2. El Director notifica al constructor cuando una parte del Producto se debe construir.
  3. El Builder maneja las peticiones del Director y agrega las partes al Producto.
  4. El Cliente el producto del Builder.

Como consecuencias de la implementación del patrón tenemos:

  • Se nos permite variar la representación interna del Producto: como el producto se construye a través de una interfaz abstracta, para cambiar la representación interna del producto basta con definir un nuevo tipo de constructor.
  • Se nos permite separar el código de la construcción y la representación.
  • Nos da un control muy fino sobre el proceso de construcción de un Producto.

Para el ejemplo vamos a coger una pizzería que es un ejemplo que podéis encontrar en muchos sitios, pero me ha parecido lo suficientemente descriptivo como para no tener que diseñar uno por mí mismo. En este caso vamos a tener:

  • Una cocina: Director
  • Las pizzas: Product
  • Las diferentes variedades de pizzas: ConcreteBuilder

Ahora vamos a rellenar esto con algo de código. En primer lugar tendremos el producto:

class Pizza {
    private String base;
    private String salsa;
    private String ingredientes;
    /* Getters y Setters */
}

En segundo lugar tendremos el Builder:

abstract class PizzaBuilder {
    protected Pizza pizza;
    public Pizza getPizza() {
        return this.pizza;
    }

    public void createPizzaProduct() {
        this.pizza = new Pizza();
    }

    public abstract void hacerBase();
    public abstract void hacerSalsa();
    public abstract void hacerIngredientes();
}

A partir de aquí tenemos los ConcreteBuilders que serán las pizzas específicas de cada tipo:

class Carbonara extens PizzaBuilder {
    public void hacerBase() {
        this.pizza.setBase(FINA);
    }

    public void hacerSalsa() {
        this.pizza.setSalsa(NATA);
    }

    public void hacerIngredientes() {
        this.pizza.setIngredientes(BACON + CEBOLLA);
    }
}

class Barbacoa extens PizzaBuilder {
    public void hacerBase() {
        this.pizza.setBase(GRUESA);
    }

    public void hacerSalsa() {
        this.pizza.setSalsa(TOMATE);
    }

    public void hacerIngredientes() {
        this.pizza.setIngredientes(CARNE + CARNE);
    }
}

class Mediterranea extens PizzaBuilder {
    public void hacerBase() {
        this.pizza.setBase(EXTRA_FINA);
    }

    public void hacerSalsa() {
        this.pizza.setSalsa(NO);
    }

    public void hacerIngredientes() {
        this.pizza.setIngredientes(ACEITUNA + ALCACHOFA);
    }
}

Y por último vamos con el Director:

class Cook {
    private PizzaBuilder pizzaBuilder;

    public void setPizzaBuilder(PizzaBuilder pb) {
        this.pizzaBuilder = pb;
    }

    public Pizza getPizza() {
        return this.pizzaBuilder.getPizza();
    }

    public void hacerPizza() {
        pizzaBuilder.createPizzaProduct();
        pizzaBuilder.hacerBase();
        pizzaBuilder.hacerSalsa();
        pizzaBuilder.hacerIngredientes();
    }
}

Vamos a por el código de la clase Main con el que ejecutar algo y ver cómo funciona:

public class Main {
    public static void main(String[] args) {
        Cook cook = new Cook();
        PizzaBuilder carbonaraB = new Carbonara();

        cook.setPizzaBuilder(carbonaraB);
        cook.hacerPizza();

        Pizza pizza = cook.getPizza();
        …
    }
}

Como nota final, hay que decir que los patrones de Abstract Factory y Builder son muy similares, ya que los dos pueden realizar la construcción de objetos complejos. La principal diferencia entre ellos es que el patrón Builder se centra en construir el objeto complejo paso a paso, mientras que el patrón Abstract Factory da más importancia a la similitud de los objetos.

Hasta aquí hemos llegado por hoy. Espero que más o menos hayamos entendido para que sirve este patrón y como implementarlo. Nos vemos.

GoF – Patrones de diseño (IV): Builder

GoF – Patrones de diseño (III): Abstract Factory

Entrando en materia vamos a empezar con los patrones. Para todo aquel que esté intentando seguir el libro, observará que me he saltado una sección, más concretamente, la del caso de estudio. Aunque la sección no está mal ni mucho menos (me la he leído únicamente por encima), creo que no tiene lugar en el objetivo de esta serie de artículos, y por este motivo, la he saltado. Pero os animo a que si estáis siguiendo el libro, hagáis una pequeña pausa antes de continuar leyendo este artículo y os lo leáis antes de seguir.

El primero de los patrones que vamos a ver es el “Abstract Factory”.

Simplificando mucho el concepto para que de cara al futuro nos quede aunque sea una idea clave en la cabeza sobre qué es este patrón, podemos decir que una Abstract Factory es una clase que nos provee de una interfaz para producir una familia de objetos. Lo que a todos los efectos es, crear una interfaz que nos permita la creación y utilización de objetos relacionados pero sin tener que definir ni especificar una clase concreta. Se suele utilizar mucho por ejemplo para la creación de widgets o interfaces gráficas que sean multiplataforma, de esta forma nos podemos abstraer del sistema concreto y realizar el desarrollo de forma genérica. Otro nombre que recibe es el de “Kit”. Personalmente, nunca había oído este nombre, pero en el libro aparece y no está de más nombrarlo (lo que dije al principio, hay que saber cómo se nombran las cosas y no solo que son). Lo que busca el patrón es ofrecer la posibilidad de trabajar con varios objetos diferentes aunque relacionados y facilitar la adhesión de nuevos objetos relacionados en un futuro para cubrir nuevas necesidades.

Como ejemplo, vamos a coger el mencionado sistema de widgets para la creación de una aplicación cliente. El problema al que nos enfrentamos a la hora de realizar una implementación, es que queremos soportar múltiples estándares, y en un futuro, quizás, añadir nuevos. Con esto la aplicación cliente no puede crear un objeto concreto:

StndAMenuBar nemu = new StdnAMenuBar();

Las aplicaciones clientes deberían trabajar con objetos y clases genéricas abstrayéndose de la implementación concreta:

MenuBar menu = Menu.createMenuBar();

De esta forma, conseguiremos que nuestro sistema sea:

  • Independiente de los procesos de creación, composición y representación de sus productos.
  • Configurable para una familia de productos
  • Solo necesitará proporcionar una librería de productos y no su implementación.

Así los elementos en nuestro desarrollo serán:

  • AbstractFactory: Interfaz para las operaciones de creación de productos abstractos.
  • ConcreteFactory: Implementa las operaciones para la creación de objetos de productos concretos
  • AbstractProduct: Declara una interfaz para los objetos de un tipo de productos.
  • ConcreteProduct: Define un objeto de producto que creará la correspondiente Concrete Factory , a la vez que implementa la interfaz de AbstractProduct.
  • Client: Será el que utilice nuestras clases abstractas.

Lo se, no os habéis enterado de nada y estáis mirando el monitor con cara de pocos amigos. No os preocupéis, seguid en vuestra mente con la frase inicial que dijimos íbamos a recordar y repasad este apartado de nuevo cuando estéis viendo el ejemplo de código.

Pero antes de pasar al código, solo un par de anotaciones sobre algunas ventajas y desventajas.

Ventajas:

  • Aísla las clases de implementación: ayuda a controlar los objetos que se creen y encapsula la responsabilidad y el proceso de creación de objetos producto.
  • Hace fácil el intercambio de familias de productos. Solo necesitaremos cambiar de factory.
  • Fomenta la consistencia entre productos.

Desventajas:

  • Para añadir un nuevo productos, se requiere la implementación de el interfaz y todos sus métodos.

Y por fin hemos llegado al código. Vamos a implementar una pequeña imprenta y los servicios que esta ofrece: Impresión a color, impresión en blanco y negro, y diseño de carteles.

Para ello vamos a implementar en primer lugar nuestro interfaz que implementarán nuestros diferentes servicios:

public interface Servicio {
    public void codigoDeServicio();
}

Ahora vamos a crear la interfaz encargada de la creación de servicios:

public interface ServicioDeImpresion {
    public Servicio crearServicio();
}

Ahora crearemos los tres servicios que ofrece nuestra imprenta:

public class ServicioColor implements Servicio {
    public void codigoDeServicio() { return COLOR; }
}

public class ServicioBandW implements Servicio {
    public void codigoDeServicio() { return B_AND_W; }
}

public class ServicioDesign implements Servicio {
    public void codigoDeServicio() { return DESIGN; }
}

Ahora vamos a crear las Factory para cada uno de los servicios:

public class ColorFactory implements ServicioDeImpresion {
    public Servicio crearServicio() { return new ServicioColor(); }
}

public class BandWFactory implements ServicioDeImpresion {
    public Servicio crearServicio() { return new ServicioBandW(); }
}

public class DesignFactory implements ServicioDeImpresion {
    public Servicio crearServicio() { return new ServicioDesign(); }
}

Finalmente, lo utilizamos en un ejemplo que creará una Factory del tipo que le pasemos como parámetro:

public class MainFactory {
    public static void createFactory(ServicioDeImpresion factoria) {
        Servicio s = factoria.crearServicio();
        int c = s.codigoDeServicio();
        ...
    }
}

Con esto tendríamos implementado nuestro patrón Abstract Factory.

Buenos, espero que os hayáis aclarado, si tenéis cualquier duda, ya sabéis, dejad un comentario. Nos vemos.

GoF – Patrones de diseño (III): Abstract Factory