PATRONES.

Anuncio
PATRONES.
Experto.
Solución:
Problema que resuelve:
Asignar una responsabilidad a la clase que tiene la información
necesaria para cumplirla.
¿Cuál es el principio fundamental en virtud del cual asignaremos
las responsabilidades a los objetos?
Durante el diseño OO, cuando se definen las interacciones entre los objetos, tomamos
decisiones sobre la asignación de responsabilidades a las clases. Si se hacen de forma
adecuada, los sistemas tienden a ser más fáciles de entender, mantener y ampliar, y se nos
presenta la oportunidad de reutilizar componentes.
Ejemplo:
En la aplicación punto de venta, alguna clase necesita conocer el gran total de la venta.
Se plantea esta pregunta: ¿Quién es el responsable de conocer el gran total de la venta?
Para calcular el total hay que conocer todas las
instancias VentasLineadeProducto de una venta y la
suma de sus subtotales. Y esto conoce únicamente la
instancia Venta; desde el punto de vista del Experto,
Venta es la clase correcta para asumir esta
responsabilidad; es el experto en información.
Para determinar el subtotal de la línea de productos se necesitan
VentasLineadeProducto.cantidad y EspecificaciondeProducto.precio; desde la perspectiva del
patrón Experto, VentasLineadeProducto debería calcular el subtotal; es el experto en
información.
VentasLineadeProducto no puede cumplir la responsabilidad de conocer y dar el subtotal, si no
conoce el precio del producto. EspecificaciondeProcucto es un Experto en información para
contestar su precio; por tanto, habrá que enviarle un mensaje preguntándole el precio.
Para cumplir con la responsabilidad de conocer y dar el total de la venta, se asignaron tres
responsabilidades a las tres clases objeto:
Clase.
Responsabilidad.
Venta:
Conoce el total de la venta.
VentasLineasdeProducto: Conoce el subtotal de la línea de
producto.
EspecificaciondeProducto: Conoce el precio del producto.
Explicación:
El Experto en Información se utiliza con frecuencia en la asignación de responsabilidades; es un
principio de guía básico que se utiliza continuamente en el diseño de objetos. El Experto
expresa la “intuición” común de que los objetos hacen las cosas relacionadas con la
información que tienen.
A menudo el cumplimiento de la responsabilidad requiere información que está dispersa por
diferentes clases de objetos. Esto implica que hay muchos expertos en información parcial que
colaborarán en la tarea.
Contraindicaciones:
En algunas ocasiones la solución que sugiere el Experto no es deseable debido a problemas de
cohesión y acoplamiento.
Beneficios:
- Se conserva el encapsulamiento, ya que los objetos se valen de su propia información
para hacer lo que se les pide. Esto soporta un bajo acoplamiento, lo que favorece al
hecho de tener sistemas más robustos y de fácil mantenimiento.
- El comportamiento se distribuye entre clases que cuentan con la información
requerida, alentando con ello definiciones de clase sencillas y más cohesivas que son
más fáciles de comprender y mantener. Así se brinda soporte a una alta cohesión.
- Bajo Acoplamiento.
- Alta Cohesión.
Creador.
Solución:
Problema que
resuelve:
Asignarle a la clase B la responsabilidad de crear una instancia de clase A
en uno de los siguientes casos:
· B agrega los objetos A.
· B contiene los objetos A.
· B registra las instancias de los objetos A.
· B utiliza específicamente los objetos A.
· B tiene datos de inicialización que serán transmitidos a A cuando este
objeto sea creado (así que B es un Experto respecto a la creación de A).
¿Quién debería ser responsable de crear una nueva instancia de alguna
clase?
B es un creador de los objetos A.
Si se puede aplicar más de una opción, B es una clase que agrega o contiene objetos de A.
Ejemplo:
En la aplicación del punto de venta, ¿quién debería encargarse de crear una instancia
VentasLineadeProducto? Desde el punto de vista del patrón Creador, deberíamos buscar una
clase que agregue, contenga y realice otras operaciones sobre ese tipo de instancias.
Una Venta contiene (agrega) muchos objetos VentasLineadeProducto; por ello, el oatrón
Creador sugiere que Venta es idónea para asumir la responsabilidad decrear las instancias
VentasLineadeProducto.
Esta asignación de responsabilidades requiere definir en Venta un método de
hacerLineadeProducto.
Explicación:
La intención básica del patrón Creador es encontrar un creador que necesite conectarse al
objeto creado en alguna situación. Eligiéndolo como creador se favorece el Bajo Acoplamiento.
Algunas veces se encuentra un creador buscando las clases que contienen los datos de
inicialización que se pasaran durante la creación.
Beneficios: se brinda soporte a un bajo acoplamiento.
Bajo acoplamiento.
Solución:
Problema que
resuelve:
Asignar una responsabilidad para mantener bajo acoplamiento.
¿Cómo dar soporte a una dependencia escasa y a un aumento de la
reutilización?
El acoplamiento es una medida de fuerza con que una clase está conectada a otras clases, con
las que conoce y con que recurre a ellas. Una clase con bajo acoplamiento no depende de
muchas otras.
Una clase con alto acoplamiento recurre a muchas otras. Presentan los siguientes problemas:
- Los cambios de las clases afines ocasionan cambios locales.
- Son más difíciles de entender cuando están aisladas.
- Son más difíciles de reutilizar porque se requiere la presencia de otras clases de las
que dependen.
Explicación:
El patrón Bajo Acoplamiento impulsa la asignación de responsabilidades de manera que su
localización no incremente el acoplamiento hasta un nivel que nos lleve a resultados negativos.
Ejemplo:
Suponiendo que se necesita crear una instancia Pago y asociarla a Venta. ¿Qué clase se
encargará de hacer esto?
Puesto que una instancia TPDV registra un Pago, el patrón Creador indica que TPDV es un buen
candidato para producir el Pago. La instancia TPDV podría entonces enviarle a Venta el
mensaje agregarPago, transmitiendo al mismo tiempo el nuevo Pago como parámetro.
Beneficios:
- No se afectan por cambios de otros componentes.
- Fáciles de entender por separado.
- Fáciles de reutilizar.
Alta cohesión.
Solución:
Problema que
resuelve:
Asignar una responsabilidad de modo que la cohesión siga siendo
alta.
¿Cómo mantener la complejidad dentro de los límites manejables?
La cohesión es una medida de cuán relacionadas y enfocadas están las responsabilidades de
una clase. Un elemento con responsabilidades altamente relacionadas y que no hace una gran
cantidad de trabajo tiene alta cohesión.
Una clase con baja cohesión hace muchas cosas no relacionadas o demasiado trabajo. No
convienen este tipo de clases pues presentan los siguientes problemas:
- Son difíciles de comprender.
- Son difíciles de reutilizar.
- Son difíciles de conservar.
- Son delicadas: les afectan constantemente los cambios.
Las clases con baja cohesión a menudo representan un alto grado de abstracción o han
asumido responsabilidades que deberían haber delegado a otros objetos.
Beneficios:
- Mejoran la claridad y la facilidad con que se entiende el diseño.
- Se simplifican el mantenimiento y las mejoras en funcionalidad.
- A menudo se genera un bajo acoplamiento.
- La ventaja de una gran funcionalidad soporta una mayor capacidad de reutilización,
porque una clase muy cohesiva puede destinarse a un propósito muy específico.
Controlador.
Solución:
Problema que
resuelve:
Asignar la responsabilidad del manejo de un mensaje de los eventos de un
sistema a una clase que represente una de las siguientes opciones:
· El sistema global: controlador de fachada.
·La empresa u organización global: controlador de fachada.
· Algo en el mundo real que es activo y que pueda participar en la tarea:
controlador de tareas.
· Un manejador artificial de todos los eventos del sistema de un caso de
uso: controlador de casos de uso.
¿Quién debería encargarse de atender un evento del sistema?
Un evento del sistema es un evento de alto nivel generado por un actor externo; es un evento
de entrada externa. Se asocia a operaciones del sistema: las que emite en respuesta a los
eventos del sistema.
Un controlador es un objeto que no pertenece a la interfaz de usuario,responsable de manejar
un evento del sistema. Define además el método de su operación.
Ejemplo:
¿Quién debería ser el controlador de eventos sistémicos como introducirProducto y
terminarVenta?
De acuerdo con el patrón Controlador, disponemos de las siguientes opciones:
- TPDV: representa el “sistema” global.
- Tienda: representa la empresa u organización global.
- Cajero: representa algo en el mundo real que está activo (por ejemplo, el papel de una
persona) y que puede intervenir en la tarea.
- ManejadordeComprarProductos: representa un manejador artificial de todas las
operaciones del sistema de un caso de uso.
Explicación:
La misma clase controlador debería utilizarse con todos los eventos sistémicos de un caso de
uso, de modo que podamos conservar la información referente al estado del caso en el
controlador. Esta información será útil para identificar los eventos del sistema fuera de la
secuencia establecida. Puede emplearse varios controladores en los casos de uso.
Un defecto frecuente al diseñar controladores consiste en asignarles demasiada
responsabilidad. Normalmente un controlador debería delegar a otros objetos el trabajo que
ha de realizarse mientras coordina la actividad.
La primera categoría de controlador es un controlador de fachada que representa al sistema
global. Es una clase que para el diseñador representa al sistema entero.
Los controladores de fachada son adecuados cuando el sistema sólo tiene unos cuántos
eventos o cuando es imposible redirigir los mensajes de los eventos del sistema a otros
controladores.
Si se elige un controlador de casos de uso entonces habrá un controlador diferente para cada
caso de uso. No es un objeto del dominio; es una construcción artificial para dar soporte al
sistema. Este controlador es una alternativa a tener en cuenta cuando la asignación de las
responsabilidades a un controlador de fachada no conduce a diseños con baja cohesión o alto
acoplamiento. Es una buena elección cuando hay muchos eventos del sistema repartidos por
diferentes procesos; el controlador factoriza la gestión en clases separadas manejables.
Resumiendo, el Controlador recibe la solicitud del servicio desde la capa de la IU y coordina su
realización, normalmente delegando a otros objetos.
Beneficios:
- Mayor potencial de los componentes reutilizables.
- Reflexionar sobre el estado del caso de uso.
Polimorfismo.
Solución:
Problema que
resuelve:
Cuando por el tipo varían las alternativas o comportamientos afines, las
responsabilidades del comportamiento se asignarán a los tipos en que el
comportamiento presenta variantes.
¿Cómo manejar las alternativas basadas en el tipo? ¿De qué manera crear
componentes software conectables?
Alternativas basadas en el tipo. La variación condicional es un tema esencial en la
programación. Si se diseña un programa mediante la lógica condicional if - then – else o case,
habrá que modificar la lógica del case cuando surja una variante. Este procedimiento dificulta
extender un programa con otras variantes, porque se tiende a necesitar los cambios en varios
lugares donde exista la lógica condicional.
Componentes de software conectables. Viendo los componentes en las relaciones clienteservidor, ¿cómo podemos reemplazar un componente por otro sin afectar al cliente?
Explicación:
Puesto que el comportamiento para la adaptación de un objeto varía según el objeto, según el
patrón Polimorfismo deberíamos asignar la responsabilidad de la adaptación a los diferentes
objetos de ese tipo, implementada con una operación polimórfica.
Estos objetos no son externos, sino objetos software locales que representan a los externos.
El Polimorfismo es un principio fundamental para diseñar cómo se organiza el sistema para
gestionar variaciones similares. Según el Polimorfismo, un diseño basado en la asignación de
responsabilidades puede ser extendido fácilmente para que realice nuevas variantes. Los
objetos requerirán poca o nula modificación si soportan las operaciones polimórficas
implementadas.
Beneficios:
 Es fácil agregar las futuras extensiones para nuevas variaciones.
 Las nuevas implementaciones se pueden introducir sin afectar a los clientes.
Fabricación Pura.
Solución:
Problema
que resuelve:
Asignar un conjunto altamente cohesivo de responsabilidades a una clase
artificial que no representa nada en el dominio del problema: una cosa
inventada para dar soporte a una alta cohesión, un bajo acoplamiento y
reutilización.
¿A quién asignar la responsabilidad cuando uno está desesperado y no
quiere violar los patrones Alta Cohesión y Bajo Acoplamiento?
Esa clase es una fabricación de la imaginación. En teoría, las responsabilidades que se asignan
brindan soporte a una alta cohesión y a bajo acoplamiento, de modo que el diseño de
fabricación sea muy limpio, o puro.
Se dan muchas situaciones donde el asignar responsabilidades exclusivamente a las clases del
dominio origina problemas por una mala cohesión o acoplamiento o bien por un escaso
potencial de reutilización.
Ejemplo:
Supongamos que se necesita soporte para guardar las instancias Venta en una base de datos
relacional. En virtud del patrón Experto, en cierto modo se justifica asignar esta
responsabilidad a la clase Venta.
Aunque en virtud del patrón Experto Venta es un candidato lógico para guardarse a sí misma
en una base de datos, da origen a un diseño de baja cohesión, alto acoplamiento y bajo
potencial de reutilización, precisamente el tipo de situación desesperada exige inventar algo.
Una solución razonable consiste en crear una clase nueva que se encargue tan sólo de guardar
los objetos en algún tipo de almacenamiento persistente: una base de datos relacional. Esta
clase es una de Fabricación Pura, una mera abstracción de la imaginación.
Crear una fabricación pura justifica su uso para lo siguiente: eliminar un diseño ineficiente, con
mala cohesión y acoplamiento y cambiar por un buen diseño que ofrezca un mayor potencial
de reutilización.
Explicación:
Para diseñar una Fabricación Pura debe buscarse ante todo un gran potencial de reutilización,
asegurándose para ello de que sus responsabilidades sean pequeñas y cohesivas. Estas clases
tienden a tener un conjunto de responsabilidades de grano fino.
Una fabricación pura suele partirse atendiendo a su funcionalidad y, por lo mismo, es una
especie de objeto de función central.
No es crítico identificar una clase como Fabricación Pura. Algunas clases software se inspiran
de acuerdo con las representaciones del dominio, y otras simplemente se crean por
conveniencia del diseñador de objetos. Estas clases de conveniencia normalmente se crean
para agrupar algún comportamiento común y por tanto, se inspiran según una
descomposición de comportamiento en lugar de una descomposición de la representación.
Dicho de otro modo, una Fabricación Pura normalmente se organiza en base a funcionalidad
relacionada.
Beneficios:
- Se brinda soporte a una Alta Cohesión porque las responsabilidades se dividen en una
clase de gano fino que se centra exclusivamente en un conjunto muy específico de
tareas afines.
- Puede aumentar el potencial de reutilización debido a la presencia de clases de
Fabricación Pura de grano fino, cuyas responsabilidades pueden utilizarse en otras
aplicaciones.
Indirección.
Solución:
Problema
que resuelve:
Se asigna la responsabilidad a un objeto intermedio para que medie entre
otros componentes o servicios, y estos no terminen directamente acoplados.
El intermedio crea una indirección entre el resto de los componentes o
servicios.
¿A quién se asignará las responsabilidades a fin de evitar el acoplamiento
directo? ¿De qué manera se desacoplarán los objetos de modo que se
obtenga un Bajo Acoplamiento y se conserve un alto potencial de
reutilización?
Explicación:
El motivo para la Indirección normalmente es el Bajo Acoplamiento; se añade un intermediario
para desacoplar otros componentes o servicios.
Beneficios: Bajo Acoplamiento.
Variaciones Protegidas.
Solución:
Problema que
resuelve:
Identifique los puntos de variaciones previstas o de inestabilidad; asigne
responsabilidades para crear una interfaz estable alrededor de ellos.
¿Cómo diseñar objetos, subsistemas y sistemas de manera que las
variaciones o inestabilidades en estos elementos no tengan un impacto no
deseable en otros elementos?
Añadiendo un nivel de indirección, una interfaz, y utilizando el polimorfismo con varias
implementaciones, se consigue proteger al sistema de las variaciones externas. Los objetos
internos colaboran con una interfaz estable; las distintas implementaciones del adaptador
ocultan las variaciones de los sistemas externos.
Beneficios:
 Se añaden fácilmente las extensiones que se necesitan para nuevas variaciones.
 Se pueden introducir nuevas implementaciones sin afectar a los clientes.
 Se reduce el acoplamiento.
 Puede disminuirse el impacto o coste de los cambios.
Adaptador.
Solución:
Problema que
resuelve:
Convierta la interfaz original de un componente en otra interfaz,
mediante un objeto adaptador intermedio.
¿Cómo resolver interfaces incompatibles, o proporcionar una interfaz
estable para componentes parecidos con diferentes interfaces?
Es un ejemplo del patrón Polimorfismo.
Factoría.
El Adaptador da lugar a un nuevo problema en el diseño: ¿quién crea el adaptador? ¿Cómo
determinar qué clase de adaptador crear?
Si los crea algún objeto del dominio, las responsabilidades de los objetos del dominio exceden
la lógica pura de la aplicación y entran en otras cuestiones relacionadas con la conexión con
componentes software externos.
Además, hay que dividir en módulos o separar intereses distintos en áreas diferentes, de
manera que cada una tenga un propósito cohesivo.
Por tanto, la elección de un objeto del dominio para crear los adaptadores no está de acuerdo
con el objetivo de separación de intereses, y disminuye su cohesión.
Una alternativa típica es aplicar el patrón Factoría (o Factoría Concreta), en el que se define un
objeto Fabricación Pura “factoría” para crear los objetos.
Los objetos Factoría tienen varias ventajas:
Separan la responsabilidad de la creación compleja en objetos de apoyo cohesivos.
Ocultan la lógica de creación potencialmente compleja.
Permiten introducir estrategias para mejorar el rendimiento de la gestión de la memoria, como
objetos caché o de reciclaje.
A menudo se accede a las factorías con el patrón Singleton.
Factoría Abstracta.
Solución:
Problema que
resuelve:
Proporciones una interfaz para crear familias de objetos relacionados o
que dependen entre sí, sin especificar sus clases concretas.
¿Cómo crear familias de clases relacionadas que implementan una
interfaz común?
Contraindicaciones: Es difícil soportar nuevas clases de productos.
Beneficios:
 Aísla a los clientes de las clases concretas de implementación.
 Favorece la consistencia entre productos.
Singleton.
Solución:
Problema que
resuelve:
Definir un método de clase o una función que no sea miembro y que
devuelve el singleton.
Permitir solo una instancia de una clase. Los objetos necesitan un
solo punto de acceso.
A veces conviene soportar la visibilidad global o un solo punto de acceso a una instancia
individual de una clase y no a alguna otra forma de visibilidad.
Puesto que la visibilidad ante las clases tiene un ámbito global, todo objeto puede llamar
directamente el método clase que devuelva el elemento considerado Singleton.
Beneficios:
 Permite el manejo de objetos únicos y que sean accesibles a otros objetos.
 Acceso controlado a la única instancia.
Descargar