sábado, 29 de diciembre de 2012

Patrón de diseño observer

Es una patrón de diseño que define una dependencia uno a muchos, de tal forma que cuando un objeto cambia de estado se notifica a los objetos dependientes, para que se actualicen automáticamente.

Voy a ilustrarlo con un ejemplo. Imaginemos que tenemos una estación meteorológica y varias personas consultan su estado constantemente aunque la temperatura no cambie. Esto no es muy óptimo y consume recursos (por ejemplo ancho de banda). Lo ideal sería que la estación meteorológica informara a sus observadores cuándo se produzca un cambio en la lectura del sensor de temperatura. Este problema se puede resolver con el patrón observer.

Estructura


Sujeto: interfaz donde se declaran e implementan (si se quiere) los métodos añadir o eliminar observadores. También incluye el método notificar encargado de actualizar los cambios.

SujetoConcreto (estación meteorológica): hereda los métodos añadir y eliminar, además posee los métodos propios, getEstado y setEstado. El método setEstado llama a notificar, que éste a su vez obliga a los observadores a consultar (getEstado) el estado de la estación meteorológica.  También almacena la variable de interés para sus observadores.

Observador: define una interfaz para los objetos a los que se deben notificar cambios en un sujeto.

ObservadorConcreto: implementa el código encargado de consultar el estado del sujeto concreto. Además almacena una copia del estado del sujeto.


Ventajas

  • Reduce el acoplamiento entre clases. Por ejemplo separar la capa de datos de la de presentación.
  • Existe una separación entre sujetos y observadores, lo que permite reutilizarlos de manera independiente.
  • Podemos añadir y quitar observadores sin tener que cambiar el sujeto ni los observadores.

FAQ
  • ¿Quien dispara la actualización?. Dos formas:
    • El sujeto concreto es el que llama al método notificar. Libera al cliente de esta operación. La desventaja es que si hay muchas actualizaciones seguidas, no es óptico y tal vez sea preferible esperar a que se realicen todos los cambios.
    • La clase cliente llama a notificar, cargándose con esa responsabilidad. 
  • ¿Cómo gestionamos la eliminación de un sujeto?
    • Notificando la eliminación a los observadores. Eliminar los observadores del sujeto no es una opción.
  • Diferencia entre el modelo pull y push.
    • Modelo pull: el sujeto envía lo mínimo, los observadores piden lo necesario. Puede ser poco eficiente.
    • Modelo push: el sujeto envía información detallada del cambio, aunque los observadores no la necesiten. Mayor acoplamiento, observadores menos reutilizables.
  • ¿Cómo especificar las notificaciones que nos interesan?
    • En los métodos añadir y actualizar , pasar otro parámetro que lo indique (además del observador y el sujeto respectivamente).

Código ejemplo: Patrón Observer


miércoles, 26 de diciembre de 2012

Patrón de diseño Iterator

Es una patrón de comportamiento.  Permite acceder a una colección de objetos de forma secuencial.

Por ejemplo, imaginemos que tenemos una colección de objetos en forma de árbol creada con el patrón composite y queremos recorrerla en preorden, inorden y postorden. Este patrón nos viene como anillo al dedo, permitiéndonos encapsular este comportamiento fuera de la estructura y ocultando al usuario la forma de recorrerla (si nos interesa).

Estructura genérica:


Roles de cada clase:
  • Iterador (Iterador): define la interfaz para acceder y recorrer los elementos de un agregado.
  • IteradorConcreto (IteradorLista o IteradorArbol): implementa la interfaz del iterador y guarda la posición actual del recorrido en cada momento.
  • Agregado (ListaAbstracta): define una interfaz para crear un objeto iterador.
  • AgregadoConcreto (Lista o Arbol): implementa la interfaz de creación de iteradores devolviendo una instancia del iterador concreto apropiado.
Algunas clases pueden tener varios roles a la vez. No es necesario tener una clase exclusiva para crear un iterador. En el siguiente código de ejemplo no incluyo la clase AgregadoConcreto ya que la estructura de árbol y el iterador los creo desde el programa principal. Código: PatronIterator

Frequency Answers and Questions

  • ¿Quién controla la iteración?. Cuando el cliente controla la iteración se dice que el iterador es externo, pero cuando lo controla el propio iterador se dice que es interno.
  • ¿Cómo de robusto es el iterador?. Un iterador es robusto cuando las inserciones y borrado no interfieren en el recorrido.
  • ¿Para qué puede servir un iterador nulo?. Puede ser útil para estructuras recursivas como las de composición (hoja de un composite).



martes, 11 de diciembre de 2012

Patrón de diseño Abstract Factory

Es una patrón de diseño creacional, su misión es crear familias de productos. En el ejemplo tenemos unas serie de productos (chasis, motor, choche), cada una tiene piezas de distintas marcas. Con Abstract Factory tenemos factorías concretas que crean los productos para una marca de coches determinada.


Cliente (Cliente): llamada a una factoría para que devuelva instancias de los productos.

AbstractFactory (CocheFactory): interfaz de las distintas factorías. Debe definir distintos métodos para obtener las distintos productos.

Factorías concretas (CocheFordF, CocheToyotaF): implementa una factoría por cada familia de productos. Se encargan de crear cada una de las familias de productos. En el ejemplo cada familia crear las piezas para una marca determinada de coche. Cada método crear suele devolver un objeto de tipo Producto (ejemplo Chasis, Motor o Coche (ya ensamblado)).

Producto Abstracto (Chasis, Motor, Coche): interfaz para cada familia de productos. En el ejemplo: Chasis, Motor, Coche.

Producto Concreto (ChasisToyota, ChasisFord, MotorToyota,...): implementa cada uno de los productos.


La ventaja de este patrón es que aislamos al cliente de la creación de todos los productos según la familia. También ocultamos la implementación de cada uno de los productos y la creación de sus familias.

Otro ejemplo podría ser la creación de interfaces gráficas. Podríamos tener una serie de elementos gráficos como ventanas y botones que según el sistema operativo su implementación es diferente. Tendríamos una factoría concreta por cada sistema operativo (Window, OSX, Linux,...).

jueves, 6 de diciembre de 2012

Patrón de diseño Singleton

Es un patrón de tipo creacional muy sencillo de implementar. Su misión es asegurar que sólo se pueda crear una o un número definido de instancias de una clase, además de ofrece un punto de acceso global a ella.

Un ejemplo podría ser un reproductor de vídeo. Normalmente los reproductores de vídeo como VLC o Windows Media sólo permiten ver un vídeo a la vez (no es un buen ejemplo ya que en este caso se hablaría de uno o varios procesos, no sólo de objetos).



Cuando definimos un atributo de tipo static, el valor de éste es compartido por todos los objetos que creamos a partir de esa clase.

Detalles de implementación:

  • La clase Singleton controla el acceso a la instancia única.
  • El patrón Singleton es una alternativa a las variables globales.
  • Permite que la clase de la que se crea una única instancia tenga subclases y trabajar con ellas.
  • Permite tener un número variable de instancias.
  • Ofrece más flexibilidad que los métodos (estáticos) de clase.

public class Singleton { 
     private static Singleton instance = null;
 
     private Singleton() { 
          // este método se define privado para evitar 
          // la creación de la clase con new 
     }

     public static Singleton Instance () { 
          // lazy instantiation 
          if (instance==null) 
               instance = new Singleton(); 
          return instance; 
     } 
}

// código cliente 
Singleton miSingleton = Singleton.Instance(); 
Singleton tuSingleton = Singleton.Instance();




-F.A.Q (preguntas que hay que hacerse cuando se implementa un singleton)

  • ¿Qué visibilidad debe tener el constructor de la clase singleton?. Utilizando private evitamos que la clase singleton pueda ser instanciada.

martes, 4 de diciembre de 2012

Patrón de diseño Factory Method


Es un patrón de diseño creacional, define una interfaz para crear un objeto, pero dejando en manos de las subclases la decisión de qué clase concreta instanciar.


Ejemplo: Aplicación que instancia distintos tipos de documentos. Código:FactoryMethod


Roles:
  • Producto(Documento): interfaz de los objetos que serán creados por el método factoría.
  • ProductoConcreto(DocWord y DocExcel): implementación de los métodos de producto(documento).
  • Creador(Aplicación): declara el método factoría (creaDocumento). Se puede definir una implementación que devuelva un objeto de tipo Producto (documental).
  • CreadorConcreto (CreaExcel y CreaWord): sobrescribe el método factoría (crearDocumento) y devuelve un objeto de tipo Producto.
Con el patrón Factory Method podemos desacoplar los productos (Word, Excel, Imágenes,...) de la aplicación.

Necesitaremos crear una clase hija de Creador por cada producto que queramos utilizar en la aplicación.

Existen dos variantes:
  • Creador es una clse abstracta y no implementa el método factoría (caso del ejemplo).
  • Creador es concreta y proporciona una implementación por defecto.



Patrón de diseño Decorator.

Es un patrón estructural que permite añadir funcionalidad a un objeto de forma dinámica, en tiempo de ejecución, algo que no se puede aplicando herencia para extender la funcionalidad.



Nada mejor que un ejemplo para ilustrar la utilidad de este patrón.
Supongamos que un determinado programa tiene distintas salidas (por consola, fichero, impresora,...).
Sin patrones de diseño podríamos resolver el problema aplicando herencia.



Salida impresora = new Impresora();
impresora.imprimir("Hola mundo");

Salida de la ejecución:
Salida por consola:Hola mundo
Salida por fichero:Hola mundo
Salida por impresora:Hola mundo

Sería una solución estática, tendría que cambiar el código (herencia entre clases) si sólo quiero sacar el texto por consola y la impresora , pero no guardarlo en el fichero. Código: SalidaSinDecorador

Mediante el patrón decorador, tendría esta estructura:


De esta forma añado funcionalidad a la consola de forma dinámica.
¿Cómo decoro la consola?

Consola consola = new Consola();
DecoradorFichero df = new DecoradorFichero(console);
DecoradorImpresora di = new DecoradorImpresora(df=
di.imprimir("Hola Mundo");

"Hola Mundo" saldría por consola, fichero e impresora. Código: SalidaDecorada
  • Consola: es el componente concreto al que queremos añadir funcionalidad
  • Salida: interfaz de los objetos.
  • Decorador: mantiene una referencia a un objeto componente y una interfaz (clase abstracta).
  • DecoradorFichero y DecoradorImpresora: añaden funcionalidad al objeto consola, al que referencia.

¿Cuál es la diferencia entre Decorator y Strategy?

En el Strategy el componente (el objeto que recibe la estrategia) cambia, mientras que con el decorador amplia la funcionalidad pero no cambia el objeto.

Patrón de diseño Composite.

Es un patrón de diseño estructural. Permite construir objetos complejos a partir de otros objetos, componiendo una estructura de árbol. Podemos manipular los objetos contenidos en el árbol de forma uniforme.

Cliente: maneja los objetos que forman parte del compuesto como componentes.

Componente (o component en inglés): clase abstracta de la que heredan todas las demás. Declara una interfaz de todos los objetos de la composición. Declara una interfaz de acceso y manipulación de los componentes hijo. Opcionalmente define una interfaz para acceder al padre de cada componente.

Compuesto o composite: define e implementa las operaciones de manejo de los hijos. Almacena a los hijos. Los objetos compuestos tratan a los objetos que contienen como instancias de tipo Componente.

Hoja (leaf): nodo hoja del árbol de objetos obtenido a partir de la estructura de clases. No tiene hijos y define el comportamiento de los objetos primitivos.

Existen dos versiones del patrón composite: transparente y seguro.

El diagrama anterior muestra la estructura de un Composite transparente. Como se puede ver las operaciones básicas están en el componente, que son heredadas por hoja y compuesto. El problema viene cuando hoja hereda operaciones que no debería manejar. Hoja no debe añadir o borrar nodos. Para solventar este problema se puede mostrar un mensaje o lanzar una excepción cuando hagamos hoja.add(componente); . 

Código del patrón composite transparente: Composite Transparente


En el composite seguro, la hoja no puede realizar operaciones que no son propias de ellas.

Código del patrón composite seguro: Composite Seguro

Debemos hacer un downcast de Componente a Compuesto.

Componente root = new Compuesto("Raiz");
Componente nodo1 = (Compuesto) new Compuesto("Nodo1");
Componente nodo2 = new Compuesto("Nodo2");
Componente nodo3 = new Compuesto("Nodo3");
Componente hoja1 = new Hoja("Hoja1");
Componente hoja2 = new Hoja("Hoja2");
Componente hoja3 = new Hoja("Hoja3");
        
//Tenemos que hacer downcast.
((Compuesto)root).add(hoja1);
((Compuesto)root).add(nodo1);
((Compuesto)nodo1).add(hoja2);
((Compuesto)nodo1).add(hoja3);
((Compuesto)nodo1).add(nodo2);
//((Compuesto)hoja1).add(hoja2); //Operación no permitida
((Compuesto)root).mostrar(1);

Podemos hacer ((Compuesto)hoja1).add(hoja2) pero como el downcast es manual debemos tener cuidado a qué objetos se lo aplicamos (recordar explicación downcast en Introducción a PPO con java.html). Podemos (compila) hacer downcast de hoja, declarada como Componente a Compuesto, pero no debemos porque JAVA lanzará una excepción ClassCastException.

Patrón de diseño Handler

Es una patrón estructural. Sirve para manejar identificadores de objetos de forma independiente de su implementación.

Permite cambiar fácilmente la implementación de los identificadores (int, String,...) hacia cualquier tipo básico o clase primitiva, sencilla o compuesta.



  • Identificable (Producto): clase cliente que necesita identificar a sus objetos mediante un identificador.
  • Handler (Handler): interfaz donde se declaran los identificadores de los objetos de la clase identificable.
  • Handler Concreto (IdLibro, IdDVD, IdCodeBar): implementación de la interfaz Handler.

Ejemplo de Handler dentro de un programa de subastas:


lunes, 3 de diciembre de 2012

Introducción a P.P.O con JAVA.

-Diferencia entre clase y objeto.

Atributos: son sustantivos que describen el objeto.
Métodos: acciones que puede realizar ese objeto.




En java para crear una instancia de una clase hacemos: new NombreClase();


-Estructura de un programa en JAVA.
class NombreClase{
     tipo static CONSTANTE=.......;
     tipo atributo = ......;

     NombreClase(){ //Constructor
     ...
     }

     NombreClase(tipo param,...){ //Constructor sobrecargado.
     ...
     }

     tipo metodo(tipo param,...){
     ...
     }

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

-Convención de mayúsculas y minúsculas en JAVA. 

  • Paquete: todas las letras en minúsculas. 
  •  Clase: 1º letra de cada palabra en mayúsculas. 
  •  Métodos: 1º letra en minúscula, mayúsculas la 1º letra de cada palabra. 
  •  Variables: igual que los métodos. 
  •  Constructores: igual que las clases. 
 No es necesario seguir la convención, pero JAVA distingue entre mayúsculas y minúsculas (key sensitive).

 -Paso de parámetros por valor o por referencia. 

  • Por referencia: se pasa un puntero de la variable referenciada (en realidad es una copia de la referencia del objeto). 
  •  Por valor: se pasa una copia del valor del parámetro. En java variables de tipo simple (int,...). 
 En JAVA las variables (simples u objetos) siempre por valor. En objetos copia de su dirección de memoria.

 -Visibilidad. 

+Pública. Visible dentro y fuera de la clase.
-Privada. Sólo dentro.
#Protegido. Sólo dentro y clases derivadas (que heredan).


-Tipos de relaciones entre clases.

  • Asociación: conexión semántica o lógica entre clases, objetos que colaboran entre sí. El tiempo de vida de uno no depende del otro.
  • Agregación: entidad que agrupa elementos, responsables de su manejo. El rombo se coloca hacia la clase que almacén los objetos.
  • Composición: relación estática. El tiempo de vida del objeto está condicionado por el tiempo de vida del que lo incluye.
  • Dependencia. Cuando su instancia depende de otro objeto.

  • Herencia o generalización. Cuando una clase hereda métodos y atributos de su clase padre. Se define en tiempo de compilación (se dice que es estática).

// extends para clases abstractas o concretas.
// implements para heredar de interfaces.
public class Hijo extends Padre{

}


-Conceptos.

  • Polimorfismo: fenómeno por el que, cuando se envía un mensaje a un objeto del que no se sabe su tipo específico se ejecuta el método adecuado de acuerdo con su tipo. Esto se consigue mediante el enlace dinámico (en tiempo de ejecución).
  • Superposición (overriding): cuando en una clase derivada se define una función que ya existe en la clase base.
  • Sobrecarga (overloading): cuando en una clase existen métodos con el mismo nombre pero distinto número de parámetros o devuelven tipos diferentes.
     Nota: la superposición se da entre clases y la sobrecarga dentro de una clase.

  • Clase abstracta. Permite implementar métodos pero no puede ser instanciada.
  • Upcasting y downcasting.


Upcasting (automático)
Mamifero m = new Gato();

Downcasting (manual)
Animal a = new Gato(); //Upcasting
Gato g = (Gato)a; //Downcasting manual. Es necesario indicar el tipo.

¿Qué pasaría si hago downcast de a, si a fue declarada como conejo? ClassCastException.


-F.A.Q
  • ¿El polimorfismo es sólo con herencia?. No, también incluye a las interfaces.
  • ¿Si una clase tiene métodos como private o protected estos se heredan?. Ver apartado visibilidad.
  • ¿Qué es una interfaz de marcado?. Una interfaz que no define métodos.
  • ¿Cuál es la diferencia entre una clase abstracta y una concreta?. Una clase abstracta no puede ser instanciada, sirve de molde para las clases derivadas (las que heredan de otra), mientras que una clase concreta puede ser instanciada.