2. A cerca de los Patrones de Diseño
Esta refcard Patrones de Diseño proporciona una rápida referencia a los 23 patrones
de diseño de Gang of Four originales, como se listan en el libro Design Patterns:
Elements of Reusable Object Oriented Sotware. Cada patrón incluye diagramas de
clase, explicación, información de uso, y un ejemplo del mundo real.
Patrones creacionales: Usados para construir objetos que pueden ser
desacoplados de su sistema de implementación.
Patrones estructurales: Usados para formar grandes estructuras de objetos
entre muchos objetos dispares
Patrones de comportamiento: Usados para manejar algoritmos, relaciones, y
responsabilidades entre objetos.
Scope del objeto: Trata con relaciones de objetos que pueden ser cambiadas en
tiempo de ejecución.
Scope de la clase: Trata con relaciones de clases que pueden ser cambiadas en tiempo
de compilación,
3. Patrones y sus tipos
Abstract Factory
Adapter
Bridge
Builder
Chain of Responsability
Command
Composite
Decorator
Facade
Factory Method
Flyweight
Interpreter
Iterator
Mediator
Memento
Prototype
Proxy
Observer
Singleton
State
Strategy
Template Method
Visitor
C
S
B
C
C
C
C
S
S
S
S
S
S
B
B
B
B
B
B
B
B
B
B
4. Chain of Responsability
Propósito
• Le proporciona a más de un objeto la oportunidad de manejar una request vinculando los
objetos de recepción.
Usado cuando:
• Múltiples objetos pueden manejar una request y la request no tiene que ser un objeto
específico.
• Un conjunto de objetos debe ser capaz de manejar una request con el handler determinado en
tiempo de ejecución.
• Una request que no está siendo manejada es una salida potencial aceptable
Ejemplo:
El manejo de excepciones en algunos lenguajes
implementa este patrón. Cuando una excepción es
lanzada en un método el runtime checa para ver si el
método tiene un mecanismo para manejar la
excepción o si debe ser pasado a la pila de llamadas.
Cuando es pasado a la pila de llamadas, el proceso se
repite hasta que el código para manejar la excepción
es encontrado o hasta que no haya más objetos padre
para manejar la request
5. Command
Propósito
• Encapsula una request permitiéndole ser tratada como un objeto. Esto permite a la request ser
manejada tradicionalmente en relaciones basadas en objetos como encolamientos y callbacks.
Usado cuando:
• Necesitas funcionalidad de callback.
• Las requests necesitan ser manejadas en tiempos variantes o en órdenes variantes.
• Es necesario un historial de requests.
• El invocador debe estar desacoplado del objeto que maneja la invocación.
Ejemplo:
Las colas de jobs son ampliamente usadas para
facilitar el procesamiento asíncrono de algoritmos.
Utilizando el patrón command, la funcionalidad a ser
ejecutada puede ser dada a una cola de jobs para
procesar sin alguna necesidad para que la queue
tenga conocimiento de la implementación real que
está invocando. El objeto command que está encolado
implementa su algoritmo particular en los confines de
la interface que la cola está esperando.
6. Interpreter
Ejemplo:
Aventuras basadas en texto, ampliamente populares en
los 1980’s proporcionan un buen ejemplo de esto.
muchos tenían comandos simples como un “step down”
que permitían recorrer el juego. Estos comandos podrían
ser anidados de forma que alteraran su significado. Por
ejemplo, “go in” resultaría en una diferente salida que
“go up”. Creando una jerarquía de comandos basada
contra el comando y el calificador la aplicación podría
fácilmente mapear muchas variaciones del comando a un
árbol de acciones relacionado.
Propósito
• Define una representación de una gramática, así como un mecanismo para comprender para
comprender y actuar contra la gramática.
Usado cuando:
• Hay una gramática a interpretar que puede ser representada como grandes árboles de sintaxis.
• la gramática es simple.
• No es importante la eficiencia.
• Es deseado el desacoplamiento de la gramática de las expresiones fundamentales.
7. Iterator
Propósito
• Permite accesar a los elementos de un objeto agregado sin permitir el acceso a su representación
fundamental, esto es, a su lógica interna.
Usado cuando:
• Se necesitan accesos a elementos sin accesar a la representación completa.
• Son necesarios múltiples o concurrentes recorridos de los elementos.
• Existen sutiles diferencias entre los detalles de implementación de varios iteradores.
• Es necesaria una interfaz uniforme para recorrido.
Ejemplo:
La implementación Java del patrón iterator permite a
los usuarios recorrer varios tipos de conjuntos de
datos sin preocuparse por la implementación
particular de la colección. Ya que los clientes
simplemente interactúan con la interface iterator, las
colecciones son dejadas para definir el iterator
apropiado para ellas mismas. Algunos permitirán
acceso completo a los conjuntos de datos particulares,
mientras que otros pueden restringir ciertas
funcionalidades, tales como remover elementos.
8. Mediator
Propósito
• Permite el débil acoplamiento encapsulando los conjuntos separados de objetos que interactúan y se
comunican con los otros. Permite a las acciones de cada conjunto de objetos variar de uno a otro
independientemente.
Usado cuando:
• La comunicación entre conjuntos de objetos está bien definida y es compleja.
• Existen muchas relaciones y es necesario un punto común de control o comunicación.
Ejemplo:
El software de lista de correos mantiene el rastro de quien
está firmado a la lista de correo y proporciona un sólo
punto de acceso a través del cual cualquier persona puede
comunicarse con la lista completa. Sin la implementación
de un mediador una persona que espera enviar un
mensaje al grupo tendría que mantener el rastreo
constantemente de quien se firmaó y quien no. Al
Implementar el patrón mediator el sistema es capaz de
recibir mensajes desde cualquier punto, luego determina
a qué bandejas enviar el mensaje, sin que el emisor del
mensaje se tenga que preocupar de la lista real de
receptores.
9. Memento
Propósito
• Permite capturar y externalizar el estado interno de un objeto de forma que pueda ser
restaurado posteriormente, todo sin violar la encapsulación.
Usado cuando:
• El estado interno de un objeto debe se guardado y restaurado en un momento posterior.
• El estado externo no puede ser expuesto por interfaces sin exponer la implementación.
• Los límites de la encapsulación deben ser preservados.
Ejemplo:
La funcionalidad deshacer puede fácilmente ser
implementada usando el patrón memento.
Serializando y deserializando el estado de un objeto
antes que el cambio ocurra podemos preservar una
instantánea de ello que puede ser posteriormente
restaurado cuando el usuario elija deshacer la
operación
10. Observer
Propósito
• Permite a uno o más objetos ser notificado de cambios de estado en otros objetos en el sistema.
Usado cuando:
• Los cambios de estado en uno o más objetos deben disparar comportamiento en otros objetos.
• Se requieren capacidades de difusión.
• Una comprensión existe que los objetos estarán cegados a expensas de notificación.
Ejemplo:
Este patrón puede ser encontrado en casi todos los
entornos de GUI. Cuando los botones, textos y otros
campos son colocados en aplicaciones, la aplicación
generalmente registra como listeners para estos
controles. Cuando un usuario dispara un evento,
como lo es hacer click en un botón, el control itera a
través de sus observers registrados y envía una
notificación a cada uno.
11. State
Propósito
• Ata las circunstancias de los objetos a sus comportamientos, permitiéndole al objeto comportarse
en diferentes formas basado contra su estado interno.
Usado cuando:
• El comportamiento de un objeto debe ser influido por su estado.
• Condiciones complejas atan el comportamiento del objeto a su estado .
• Las transiciones entre estados necesitan ser explícitas.
Ejemplo:
Un objeto email puede tener varios estados, todos de los
cuales cambiarán como el objeto maneje diferentes
funciones. Si el estado es “no enviado” entonces la llamada a
send() va a enviar el mensaje mientras que una llamada a
recallMessage() ya sea que lance un error o haga nada. Sin
embargo, si el estado es “enviado” entonces la llamada a
send() ya sea que lance un error o haga nada mientras la
llamada a recallMesage() intentará enviar una notificación a
las bandejas. Para evitar sentencias condicionales en la
mayoría o todos los métodos habría múltiples objetos state
que manejen la implementación con respecto a su estado
particular. Las llamadas en el objeto Email sería entonces
delegadas abajo al objeto state apropiado para que la maneje.
12. Strategy
Propósito
• Define un conjunto de algoritmos encapsulados que pueden ser intercambiados para llevar a
cabo un comportamiento específico.
Usado cuando:
• La única diferencia entre muchas clases relacionadas es su comportamiento.
• Son requeridas múltiples versiones o variaciones de un algoritmo.
• Algoritmos que accesen o utilicen datos que llaman código no deben ser expuestos.
• El comportamiento de una clase debe ser definida en tiempo de ejecución.
• Las sentencias condicionales son complejas y difíciles de mantener.
Ejemplo:
Cuando se importan datos en un nuevo sistema
diferentes algoritmos de validación pueden ser
ejecutados basados en el conjunto de datos. Por
medio de la configurando del import para qué
estrategias la lógica condicional para determinar qué
conjunto de validación a ejecutar puede ser removido
y el import pueda ser desacoplado del código de
validación real. Esto nos permitirá dinámicamente
llamar a una o más estrategias durante el import.
13. Template Method
Propósito
• Identifica el framework de un algoritmo, permitiendo implementar las clases para definir el
comportamiento real.
Usado cuando:
• Una sola implementación abstracta de un algoritmo es necesaria.
• El comportamiento común entre subclases debe ser localizado a una clase común.
• Las clases padre deben ser capaces de invocar comportamiento uniformemente en sus subclases.
• La mayoría o todas las subclases necesitan implementar el comportamiento.
Ejemplo:
Una clase padre InstantMessage, posiblemente tendrá todos los
métodos requeridos para manejar el envío de un mensaje. Sin
embargo, la serialización real de los datos a enviar puede variar
dependiendo de la implementación. Un mensaje de video y un
mensaje de texto plano requerirán diferentes algoritmos con fin de
serializar los datos correctamente. Las subclases de InstantMessage
pueden proporcionar su propia implementación del método de
serialización, permitiéndole a la clase padre trabajar con ellas sin
comprender los detalles de su implementación.
14. Visitor
Propósito
• Permite a una o más operaciones ser aplicadas a un conjunto de objetos en tiempo de ejecución,
desacoplando las operaciones de la estructura del objeto.
Usado cuando:
• La estructura del objeto debe tener muchas operaciones no relacionadas ejecutadas contra ella.
• La estructura del objeto no puede cambiar pero las operaciones ejecutadas en él pueden.
• Las operaciones deben ser ejecutadas en las clases concretas de la estructura de un objeto.
• Exponer el estado interno u operaciones de la estructura del objeto es inaceptable.
• Las operaciones deben ser capaces de operar en múltiples estructuras de objetos que implementan
los mismos conjuntos de interfaces.
Ejemplo:
Calcular impuestos en diferentes regiones sobre
conjuntos de facturas requeriría muchas
variaciones diferentes de lógica de cálculo.
Implementando un visitor permite a la lógica
estar desacoplada de los elementos de línea y
factura. Esto permite a la jerarquía de elementos
ser visitadas por el código de cálculo que puede
entonces aplicar a las tarifas adecuadas para la
región. Cambiar regiones es tan simple como
sustituir un visitor diferente.
15. Adapter
Propósito
• Permite que clases con interfaces diferentes trabajen juntas creando un objeto común por el cual
puedan comunicarse e interactuar.
Usado cuando:
• Una clase a ser usada no reúne los requerimientos de interface.
• Condiciones complejas atan el comportamiento del objeto a su estado.
• Las transiciones entre estados necesitan ser explícitas.
Ejemplo:
Una aplicación de facturación necesita interactuar con
una aplicación de RH con el fin de intercambiar datos
de empleados, sin embargo cada una tiene su propia
interface e implementación para el objeto Empleado.
Además, el SSN está almacenado en formatos
diferentes por cada sistema. Creando un adapter
podemos crear una interface común entre las dos
aplicaciones que les permite comunicarse usando sus
objetos nativos y es capaz de transformar el formato
SSN en el proceso.
16. Bridge
Propósito
• Define una estructura de objeto abstracta independientemente de la estructura del objeto de
implementación con el fin de limitar el acoplamiento.
Usado cuando:
• Las abstracciones e implementaciones no deben estar vinculadas en tiempo de compilación.
• Las abstracciones e implementaciones deben ser independientemente extensibles.
• Cambios en la implementación de una abstracción no deben impactar en los clientes.
• Los detalles de implementación deben estar escondidos del cliente
Ejemplo:
La JVM tiene su propio conjunto nativo de funciones
que abstraen el uso de windowing, logging del
sistema, y ejecución de byte code, pero la
implementación real de estas funciones es delegada al
sistema operativo en el que la JVM está corriendo.
Cuando una aplicación instruye a la JVM de presentar
una ventana delega la llamada a presentación a la
implementación concreta de la JVM que sabe cómo
comunicarse con el sistema operativo con el fin de
presentar la ventana.
17. Composite
Propósito
• Facilita la creación de jerarquía de objetos donde cada objeto puede ser tratado de forma
independiente como un conjunto de objetos anidados a través de la misma interface.
Usado cuando:
• Son necesarias representaciones jerárquicas de objetos.
• Los objetos y composiciones de objetos deben ser tratadas uniformemente.
Ejemplo:
A veces la información desplegada en un carrito de
compras es el producto de un sólo ítem mientras que
otras veces es una agregación de múltiples elementos.
Implementado ítems como compuestos podemos
tratar los agregados y los ítems de la misma forma,
permitiéndonos simplemente iterar sobre el árbol e
invocar funcionalidad en cada ítem. Llamando al
método getCost() en cualquier nodo dado obtendría el
costo de ese ítem mas el costo de todos los ítems
hijos, permitiéndole a los ítems ser tratados
uniformemente si ellos eran ítems solos o grupos de
ítems.
18. Decorator
Propósito
• Permite la envoltura dinámica de objetos con el fin de modificar sus responsabilidades y
comportamientos existentes.
Usado cuando:
• Las responsabilidades y comportamientos de los objetos deben ser dinámicamente modificables.
• Las implementaciones concretas deben estar desacopladas de responsabilidades y comportamientos.
• Subclasificar para llevar a cabo modificaciones es impráctico o imposible.
• La funcionalidad específica no debe residir alta en la jerarquía de objetos.
• Una cantidad de pocos objetos rodeando a una implementación concreta es aceptable
Ejemplo:
Muchos conjuntos de negocios suben sus sistemas de mail
para tomar ventaja de los decorators. Cuando los mensajes
son enviados desde alguien en la compañía a una dirección
externa el servidor de mail decora el mensaje original con
información de copyright y confidencialidad. Tan pronto como
el mensaje permanece interno la información no es agregada.
Esta decoración le permite al mismo mensaje permanecer sin
cambio hasta que una decisión de ejecución se haga para
envolver el mensaje con información adicional.
19. Facade
Propósito
• Proporciona una sola interface a un conjunto de interfaces en un sistema.
Usado cuando:
• Una sola interface es necesaria para proporcionar acceso a un sistema complejo.
• Hay muchas dependencias entre implementaciones del sistema y clientes.
• Los sistemas y subsistemas deben estar en capas.
Ejemplo:
Exponiendo un conjunto de funcionalidades a través
de un web service el código cliente sólo necesita
preocuparse sobre la sola interface que está siendo
expuesta a ellos y no a las relaciones complejas que
pueden o no existir tras la capa de web service. Una
sola llamada a servicio que puede actualizar un
sistema con nuevos datos realmente puede involucrar
comunicación con muchas bases de datos y sistemas,
sin embargo este detalle está escondido debido a la
implementación del patrón facade.
20. Flyweight
Propósito
• Facilita la reutilización de muchos objetos de grano fino, haciendo la utilización de grandes números
de objetos más eficiente.
Usado cuando:
• Muchos objetos son usados y el costo de almacenamiento es alto.
• La mayoría de cada uno de los estados del objeto pueden ser hechos extrínsecos.
• Algunos objetos compartidos pueden remplazar a muchos no compartidos.
• La identidad de cada objeto no importa
Ejemplo:
Los sistemas que permiten que los usuarios definan sus
propios flujos de aplicaciones frecuentemente tienen una
necesidad de mantener el rastreo de grandes números de
campos, páginas, y otros elementos que son casi idénticos
unos con otros. Haciendo estos elementos en flyweights todas
las instancias de cada objeto pueden compartir el estado
intrínseco mientras mantienen separado el estado extrínseco.
El estado intrínseco almacenaría las propiedades compartidas,
tales como la forma en que un textbox se ve, cuantos datos
puede contener, y qué eventos expone. El estado extrínseco
almacenaría las propiedades no compartidas, tales como las
pertenencias del elemento, cómo reaccionar ante el click de un
usuario, y cómo manejar eventos.
21. Proxy
Propósito
• Permite para el control de acceso a nivel de objeto actuar como un pase a través de una entidad
o un marcador de posición de objeto.
Usado cuando:
• El objeto que está siendo representado es externo al sistema.
• Los objetos necesitan ser creados bajo demanda.
• Se requiere control de acceso para el objeto original.
• Se requiere funcionalidad agregada cuando un objeto es accesado
Ejemplo:
Aplicaciones de libro mayor frecuentemente proporcionan
una forma de reconciliar sus declaraciones bancarias con sus
datos de libro mayor bajo demanda, automatizando muchos
de los procesos. La operación real de comunicarse con una
tercera parte es una operación relativamente cara que debe
limitarse. Mediante el uso de un proxy para representar el
objeto comunicaciones podemos limitar el número de veces o
los intervalos en que la comunicación es invocada. Además,
podemos envolver la instanciación compleja del objeto
comunicación dentro de la clase proxy, desacoplando el
código de invocación de los detalles de implementación.
22. Abstract factory
Propósito
• Provee una interface que delega las llamadas a creación a una o más clases concretas con el fin de liberar
objetos específicos.
Usado cuando:
• La creación de objetos debe ser independiente del sistema que los está utilizando.
• Los sistemas deben ser capaces de usar múltiples familias de objetos.
• Las familias de objetos deben ser usadas juntas.
• Las librerías deben ser publicadas sin exponer los detalles de implementación.
• Las clases concretas deben estar desacopladas de los clientes.
Ejemplo:
Los editores de email permitirán editar en múltiples formatos
incluyendo texto plano, texto rico, y HTML. Dependiendo del
formato que esté siendo usado, necesitan crearse diferentes
objetos. Si el mensaje es texto plano entonces podría ser un
objeto body que representara sólo texto plano y un objeto
attachment simplemente encriptaría el attachment en base
64. Si el mensaje es HTML entonces el objeto body
representaría HTML codificado y el objeto attachment
permitiría la representación inline y un attachment estándar.
Utilizando un abstract factory para la creación podemos
asegurar que el conjunto de objetos apropiados serán creados
basados contra el estilo de email que está siendo enviado.
23. Builder
Propósito
• Permite la creación dinámica de objetos basados contra algoritmos intercambiables fácilmente.
Usado cuando:
• Los algoritmos de creación de objetos deben estar desacoplados del sistema.
• Se requieren múltiples representaciones de algoritmos de creación.
• La adición de funcionalidad de nueva creación sin cambiar el código core es necesaria.
• Se requiere control en tiempo de ejecución sobre el proceso de creación.
Ejemplo:
Una aplicación de transferencia de archivos
posiblemente podría usar diferentes protocolos para
enviar archivos y el objeto de transferencia real que
será creado será directamente dependiente del
protocolo elegido. Usando un builder podemos
determinar el builder correcto a usar para instanciar el
objeto correcto. Si la elección es FTP entonces builder
FTP sería usado cuando se crea el objeto.
24. Factory Method
Propósito
• Expone un método para crear objetos, permitiéndole a las subclases controlar el proceso de
creación real.
Usado cuando:
• Una clase no sabrá qué clases le requerirán crear.
• Las subclases pueden especificar qué objetos deben ser creados.
• Las clases padre desean diferir la creación a sus subclases.
Ejemplo:
Muchas aplicaciones tienen algunas estructuras de
usuarios y grupos para seguridad. Cuando la aplicación
necesita crear un usuario, generalmente delegará la
creación del usuario a múltiples implementaciones del
usuario. El objeto usuario padre manejará la mayoría de
las operaciones para cada usuario pero las subclases
definirán el método factory que maneja la distinción en la
creación de cada tipo de usuario. Un sistema puede tener
los objetos AdminUser y StandardUser cada uno de los
cuales extiende del objeto User. El objeto AdminUser
puede ejecutar algunas tareas extra para asegurar el
acceso mientras que el objeto StandardUser puede hacer
lo mismo para limitar el acceso.
25. Prototype
Propósito
• Crear objetos basados contra una plantilla de objetos existentes a través de la clonación.
Usado cuando:
• La composición, creación y representación de objetos debe estar desacoplado de un sistema.
• Las clases a crear son especificadas en tiempo de ejecución.
• Existe un número limitado de combinaciones de estado en un objeto.
• Se requiere que los objetos o estructuras de objetos sean idénticas o semejantes a otros objetos
existentes o estructuras de objetos.
• La creación inicial de cada objeto es una operación costosa.
Ejemplo:
Los dispositivos de procesamiento de tarifas requieren la
búsqueda de muchos valores de configuración diferentes,
haciendo la inicialización del dispositivo un proceso
relativamente costoso. Cuando múltiples instancias del
dispositivo son necesarias, dígase para importar datos en
forma multi hilo, el costo de inicializar muchos dispositivos es
alto. Utilizando el patrón prototype podemos asegurar que
solamente una copia del dispositivo tiene que ser inicializada
entonces simplemente clonar el dispositivo para crear un
duplicado del objeto ya inicializado. El beneficio agregado de
esto es que los clones pueden ser racionalizados para que
solamente incluyan los datos relevantes para su situación.
26. Singleton
Propósito
• Asegura que sólo una instancia de la clase es permitida en un sistema.
Usado cuando:
• Se requiere exactamente una instancia de una clase .
• Es necesario el acceso controlado a un sólo objeto.
Ejemplo:
La mayoría de los lenguajes proporcionan algún
ordenamiento de objetos del sistema o entorno que
permite al lenguaje interactuar con el sistema operativo
nativo. Ya que la aplicación está físicamente corriendo en
sólo un sistema operativo sólo hay una necesidad cada vez
para una sola instancia de este objeto del sistema. El
patrón singleton sería implementado por el runtime del
lenguaje para asegurar que sólo una copia del objeto del
sistema es creado y asegura que sólo a los procesos
apropiados se les permite accesarlos.
27. GRACIAS
No olvides visitar nuestra página en Facebook y
regalarnos un Like.
www.facebook.com/JavaDevelopersMexico
¡Descarga y Comparte!