Post on 28-Jan-2016
Realizado por:
Manuel González 02-34995
Joaquín Windmuller 02-35564
José Lorenzo Rodríguez 02-35389
DECORATOR- Responsabilidades a un objeto
Motivación
• Se desea adicionar responsabilidades a un objeto, pero no a toda la clase.
• Las responsabilidades se pueden adicionar por medio de los mecanismos de Herencia, pero este mecanismo no es flexible porque la responsabilidad es adicionada estáticamente.
Motivación
• La solución flexible es la de rodear el objeto con otro objeto que es el que adiciona la nueva responsabilidad. Este nuevo objeto es el Decorator.
Aplicación
Adicionar responsabilidades a objetos individuales dinámicamente sin afectar otros objetos.
Para agregar responsabilidades que pueden ser retiradas.
Cuando no es práctico adicionar responsabilidades por medio de la herencia.
EjemploComponente: Interfaz
común a todas las clases susceptibles de ser ampliadas con el Decorador.
ComponenteConcreto: Son las clases cuya funcionalidad se puede extender y en las que se delega en última instancia para realizar las operaciones propias de la clase.
EjemploDecorador: Clase abstracta
que declara la estructura común a todos los Decoradores y declara (o implementa, según sea el caso) la responsabilidad de mantener una referencia al objeto que se extiende. Es posible que sobrecargue todos los métodos de la clase Componente con llamadas al componente concreto, de forma que aquellos métodos cuya funcionalidad no se extiende simplemente llaman a los originales.
Ejemplo
DecoradorConcreto1 y DecoradorConcreto2: Son clases concretas que heredan de Decorador e implementan las extensiones de funcionalidad de la clase original ComponenteConcreto.
Problema a Solucionar
Supongamos que tenemos una clase existente Ventana y queremos añadirle funcionalidad para que muestre un borde alrededor. Podemos crear una subclase VentanaConBorde que herede de Ventana.
Hasta aquí todo bien, pero supongamos que surge la necesidad de crear una ventana que muestre un pequeño botón de ayuda con un signo de interrogación (?) en su parte superior. Entonces tenemos las siguientes opciones:
Soluciones propuestasCrear otra subclase de Ventana: VentanaConBotónDeAyuda.
Problema: No cubre la necesidad de tener ventanas con bordes y botón de ayuda a la vez.
Crear una subclase de VentanaConBorde: VentanaConBordeYBotonDeAyuda. Problema: No tenemos una ventana con botón de ayuda y sin borde.
Crear clases para todas las combinaciones posibles de funcionalidades. Problema: Con este ejemplo tendríamos cuatro clases: Ventana, VentanaConBorde, VentanaConBotonDeAyuda y VentanaConBordeYBotonDeAyuda; con tres funcionalidades tendríamos ocho clases y con cuatro, ¡dieciséis!. Para n funcionalidades se necesitan 2n clases.
SoluciónSe crea a partir de Ventana la
subclase abstracta VentanaDecorador y, heredando de ella, BordeDecorador y BotonDeAyudaDecorador. VentanaDecorador encapsula el comportamiento de Ventana y utiliza composición recursiva para que sea posible añadir tantas "capas" de Decorators como se desee. Podemos crear tantos Decoradores como queramos heredando de VentanaDecorador
Ventajas
Más flexible que la herencia: responsabilidades pueden añadirse y eliminarse en tiempo de ejecución.
Diferentes decoradores pueden ser conectados a un mismo objeto.
Reduce el número de propiedades en las clases de la parte alta de la jerarquía.
Es simple añadir nuevos decoradores de forma independiente a las clases que extienden.
Sistemas con muchos y pequeños objetos.
Reglas de uso
Implica utilizarlo si…una jerarquía de clases tiene muchos niveles.
No se cumple si…entre una interfaz y su implementación no hay
una abstracción.
COMPOSITE- Jerarquías con interfaz uniforme
Intención
• El patrón Composite sirve para construir objetos complejos a partir de otros más simples y similares entre sí, gracias a la composición recursiva y a una estructura en forma de árbol.
• Esto simplifica el tratamiento de los objetos creados, ya que al poseer todos ellos una interfaz común, se tratan todos de la misma manera.
Motivación
Objetivos
• Diferentes elementos de construcción (lineas, rectángulos, círculos, etc).
• El usuario puede agrupar elementos para generar otros más complejos (De forma recursiva)
Motivación
Solución
• Clases para representar los elementos básicos
• Clases para representar contenedores de esos elementos
Ejemplo
Draw()Add(Graphic)Remove(Graphic)GetChild(int)
Graphic
Draw()
Line
Draw()
Rectangle
Draw()
Text
Draw()Add(Graphic)Remove(Graphic)GetChild(int)
Picture
graphics
Aplicación
Para representar jerarquías de objetos del estilo “parte-todo”
Se quiere presentar una interfáz uniforme para el manejo de objetos y de composiciones de ellos.
Abstracción
Client
children
Operation()Add(Component)Remove(Component)GetChild(int)
Component
Operation()Add(Component)Remove(Component)GetChild(int)
CompositeLeaf
MotivaciónaComposite
aLeafaComposite aLeaf
aLeafaLeaf aLeaf
Elementos
Component (Graphic)
• Declara el interfaz para los objetos en la composición.
• Implementa el comportamiento por defecto del interfaz común a todas las clases.
• Declara un interfaz para acceder y manejar a los componentes hijos. (opcional) define un interfaz para acceder al componente padre.
Elementos
Leaf (Rectangle, Line, Text, etc.) Representa un objeto hoja en la composición. Una
hoja no tiene hijos. Define el comportamiento de las primitivas de la
composición.
Elementos
Composite (Picture) Define el comportamiento de los componentes que
tienen hijos. Almacena los hijos. Implementa las operaciones relacionadas con los
hijos en el interfaz de Component.
Elementos
Client Manipula los objetos de la composición a través de
la interfáz Component.
Ventajas
Define jerarquías de objetos primitivos y objetos compuestos.
Permite clientes más simples (no se deben preocupar si están tratando con un objeto primitivo o uno compuesto)
Es sencillo añadir nuevos componentes.
Desventajas
Puede hacer el diseño demasiado general. Es difícil restringir los componentes de un
Composite.
Implementación
Referencias explícitas a los padres. Compartir componentes (Reducción de espacio en
memoria). “Caching” para mejorar el rendimiento. Maximizar la interfaz componente. Declarar las operaciones de los hijos. Ordenar los hijos.
VISITOR- Separar la lógica de la estructura
Intención
• Encapsular una operación que se desea efectuar a los elementos de una estructura de datos.
• De esta manera, se puede cambiar la operación sin tener que modificar ninguna de las clases sobre las que se efectúa la misma.
• Permite hacer una separación entre la estructura de datos y los algoritmos usados sobre ella
Motivación
Objetivos
• Posibilidad de generar algoritmos independientes del código de las clases sobre los que opera el mismo.
• Hay posibilidad que no se tenga acceso al código de objetos sobre los cuales queremosefectuar operaciones.
Motivación
Solución
• Cada nodo de la estructura de datos “acepta” un Visitor, el cual envía un mensaje al Visitor que incluye la clase nodo.
• De esta manera, el Visitor ejecuta el algoritmo para dicho elemento. Este proceso es conocido como “Double Dispatching” .
Implementación
Ejemplointerface Visitor {
void visit(Wheel wheel);
void visit(Engine engine);
void visit(Body body);
void visit(Car car);
}
interface Visitable {
void accept(Visitor visitor);
}
class Engine implements Visitable {
private String name;
Engine(String name) {
this.name = name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class Car implements Visitable {
}
public void accept(Visitor visitor) {
visitor.visit(this);
engine.accept(visitor);
}
}
}
Ejemploclass PrintVisitor implements Visitor {
public void visit(Wheel wheel) {
System.out.println("Visiting "+ wheel.getName()
+ " wheel");
}
public void visit(Engine engine) {
System.out.println("Visiting engine");
}
public void visit(Body body) {
System.out.println("Visiting body");
}
public void visit(Car car) {
System.out.println("Visiting car");
} ...
Elementos
Visitable
• Declara el interfaz para los objetos en la jerarquía, deben implementar el metodo accept()
• Implementa el llamado a accept(Visitor) de cada uno de sus sub-elementos
• El metodo accept debe llamar al metodo visit() del Visitor
Elementos
Visitor Representa la interfasz de un algoritmo sobre la
jerarquía Cada visitor concreto debe implementar visit()
Elementos
Client Llama los metodos concretos de visit() sobre la
estructura de datos.
Ventajas
Separación limpia entre las clases de la estructura de datos y las operaciones que se pueden realizar sobre ella.
Permite agregar operaciones sobre la estructura si afectar el resto del código
Da la posibilidad de conocer el “estado” de cada Visitor. Lo cual no se podría hacer con simple sobrecarga de métodos. Esto es util cuando la operación depende de corridas anteriores.
Desventajas Puede convertirse en un diseño innecesario puesto
que no es común que ls operaciones sobre una estructura crezcan.
La nomenclatura generica Visitable-Visitor puede confundir en el entendimiento de lo que deben hacer los algoritmos.
No siempre se puede implementar en el caso de no poseer el codigo fuente de la jerarquia.
Si no se pensó el patrón desde un comienzo, la preparación necesaria es costosa
Consejos
Utilizar las capacidades reflexivas del lenguaje (si las tiene) para evitar el uso de los metodos accept() y visit() en todas las clase.
En lenguajes funcionales Visitor puede ser entendido como un functor.
No es necesario en lenguajes con multi-dispatching