TALLER DE PATRONES DE DISEÑO



Documentos relacionados
UNIDAD 2: Abstracción del Mundo real Al Paradigma Orientado a Objetos

PROGRAMACIÓN ORIENTADA A OBJETOS Master de Computación. II MODELOS y HERRAMIENTAS UML. II.2 UML: Modelado de casos de uso

Curso de Java POO: Programación orientada a objetos

UNIVERSIDAD CATOLICA DE COLOMBIA FACULTAD DE INGENIERIA DE SISTEMAS

Patrones Creacionales Builder. Patrones Creacionales Abstract Factory. Patrones Creacionales Singleton. Patrones Creacionales Prototype

2.2.- Paradigmas de la POO

3.1 INGENIERIA DE SOFTWARE ORIENTADO A OBJETOS OOSE (IVAR JACOBSON)

Elementos requeridos para crearlos (ejemplo: el compilador)

Introducción. Ciclo de vida de los Sistemas de Información. Diseño Conceptual

Diseño orientado al flujo de datos

Patrones para persistencia (I) Ingeniería del Software II

ARQUITECTURA DE DISTRIBUCIÓN DE DATOS

En cualquier caso, tampoco es demasiado importante el significado de la "B", si es que lo tiene, lo interesante realmente es el algoritmo.

M III ABSTRACCIÓN Y CLASIFICACIÓN

Capitulo III. Diseño del Sistema.

Diseño orientado a los objetos

Ciclo de vida y Metodologías para el desarrollo de SW Definición de la metodología

GESTIÓN DOCUMENTAL PARA EL SISTEMA DE CALIDAD

Creación y administración de grupos de dominio

Arquitectura de Aplicaciones

Estas visiones de la información, denominadas vistas, se pueden identificar de varias formas.

Propuesta de Portal de la Red de Laboratorios Virtuales y Remotos de CEA

PROGRAMACIÓ DIDÁCTICA: Secuanciación, Temporalización y Unidades Didácticas

Patrones de Diseño Orientados a Objetos 2 Parte

implantación Fig. 1. Ciclo de vida tradicional

SINAUTO. (Captura Requirimientos) GRUPO 03

UNIDAD DIDACTICA 3 USUARIOS Y GRUPOS EN REDES WINDOWS 2003 SERVER II

Capítulo 1 Documentos HTML5

5.4. Manual de usuario

Patrones de Alto nivel: Patrones de Arquitectura Patrones de nivel medio: Patrones de Diseño Patrones de bajo nivel: Idioms

Java Inicial (20 horas)

Programación Orientada a Objetos en Java

Patrones de software y refactorización de código

Capítulo 12: Indexación y asociación

CAPÍTULO 3 Servidor de Modelo de Usuario

Programación Orientada a Objetos con Java

GUÍA TÉCNICA PARA LA DEFINICIÓN DE COMPROMISOS DE CALIDAD Y SUS INDICADORES

Introducción a la Programación Orientada a Objetos (POO) Introducción a la Programación Orientada a Objetos (POO)

DEPARTAMENTO: Informática. MATERIA: Programación. NIVEL: 1º Desarrollo de Aplicaciones Multiplataforma

Introducción a Protégé

Modelo de Objetos Distribuidos

Adaptación al NPGC. Introducción. NPGC.doc. Qué cambios hay en el NPGC? Telf.: Fax.:

Operación Microsoft Access 97

Guía rápida de la Oficina Virtual Área Web y Administración Electrónica

Prototipo de un sistema. interactivo de soporte y ayuda a los compradores de un centro. comercial de equipamiento del hogar

El Proceso Unificado de Desarrollo de Software

Diagrama de Clases. Diagrama de Clases

Sistemas de archivos distribuidos. Alvaro Ospina Sanjuan

GENERACIÓN DE CÓDIGO

El ABC del ERP. (Christopher Koch)

Bases de datos en Excel

En términos generales, un foro es un espacio de debate donde pueden expresarse ideas o comentarios sobre uno o varios temas.

Capítulo 4 Patrones y Patrones de Diseño (ii)

SOLUCION PARCIAL TASK SCHEDULER. Task Scheduler

Base de datos en Excel

Oficina Online. Manual del administrador

PLAN DE MEJORAS. Herramienta de trabajo. Agencia Nacional de Evaluación de la Calidad y Acreditación

MANUAL DE AYUDA HERRAMIENTA DE APROVISIONAMIENTO

Introducción a los Tipos Abstractos de Datos

GENERACIÓN DE ANTICIPOS DE CRÉDITO

UNIVERSIDAD DE SALAMANCA

Figura 4.1 Clasificación de los lenguajes de bases de datos

Tema 4. Gestión de entrada/salida

Ejercicios - Persistencia en Android: ficheros y SQLite

PATRONES. Experto. Solución:

UAM MANUAL DE EMPRESA. Universidad Autónoma de Madrid

Manual CMS Mobincube

Fundamentos del diseño 3ª edición (2002)

MANUAL DE USUARIO APLICACIÓN SYSACTIVOS

Capítulo 4. Requisitos del modelo para la mejora de la calidad de código fuente

La ventana de Microsoft Excel

DISEÑO DE FUNCIONES (TRATAMIENTOS)

CLASE 10: MÁS PATRONES. Universidad Simón Bolívar. Ing. de Software. Prof. Ivette C. Martínez

GENERACIÓN DE TRANSFERENCIAS

MANUAL DE USUARIO Y EJEMPLO DE UTILIZACIÓN HERRAMIENTA DLP-DELPHI LEARNING PACKAGE

Decisión: Indican puntos en que se toman decisiones: sí o no, o se verifica una actividad del flujo grama.

MACROS. Automatizar tareas a través del uso de las macros.

/05/2009

comunidades de práctica

Un primer acercamiento a la CMDB.

Plataforma e-ducativa Aragonesa. Manual de Administración. Bitácora

TEMA 8: DIAGRAMA DE CLASE EN UML

Metodologías de diseño de hardware

Comunicación interna: Intranets


MANUAL DE USUARIO DE LA APLICACIÓN DE ACREDITACION DE ACTIVIDADES DE FORMACION CONTINUADA. Perfil Entidad Proveedora

Sistema de Facturación de Ventas WhitePaper Enero de 2007

App para realizar consultas al Sistema de Información Estadística de Castilla y León

GUIA PROGRAMACIÓN ORIENTADA A OBJETOS

a) Cita y comenta brevemente los grados de acoplamiento. Clasifícalos y ordénalos en orden creciente al nivel de acoplamiento asociado.

CONCEPTOS BASICOS. Febrero 2003 Página - 1/10

Creación y administración de grupos locales

DCU Diagramas de casos de uso

ÍTEMS DEL MENÚ CREACIÓN Y GESTIÓN (Última revisión: lunes, 9 de marzo de 2009)

Gestión de la Configuración

1.1.- Objetivos de los sistemas de bases de datos Administración de los datos y administración de bases de datos Niveles de Arquitectura

Universidad acional Experimental Del Táchira Decanato de Docencia Departamento de Ingeniería en Informática

Introducción a la programación orientada a objetos

Tutorial de UML. Introducción: Objetivos: Audiencia: Contenidos:

Manual para la utilización de PrestaShop

Transcripción:

TABLA DE CONTENIDOS Presentación de los patrones de diseño 3 Contextualización 3 Programación Estructurada VS Programación Orientada a Objetos (POO) 3 Por qué debemos conocer los patrones de diseño? 7 Qué es un patrón? 7 Consecuencias del uso de patrones de diseño 9 Clasificación de patrones de diseño 10 Objetivos del taller 11 Requisitos 11 TALLER DE PATRONES DE DISEÑO Raquel Trillo Lado Patrones Estructurales 12 El patrón Composite o Composición 12 El patrón Proxy 22 El patrón Decorator o Decorador 29 El patrón Facade o Fachada 39 El patrón Bridge o Puente* 43 El patrón Adapter o Adaptador* 45 El patrón Flyweight o Objeto Ligero* 49 Patrones de Creación 54 El patrón Prototype o Prototipo 54 El patrón Singleton o Instancia única* 58 El patrón Factory Method o Método de fabricación* 60 El patrón Abstract Factory o Fábrica abstracta* 63 El patrón Builder o Constructor* 65 Patrones de Comportamiento 68 El patrón Chain of Responsability o Cadena de Responsabilidad 68 El patrón State o Estado 73 El patrón Strategy o Estrategia 78 El patrón Observer u Observador 82 El patrón Iterator o Iterador* 89 El patrón Template Method o Plantilla* 92 El patrón Visitor o Visitante* 95 El patrón Command o Comando* 98 El patrón Memento o Recuerdo* 102 El patrón Mediator o Mediador* 104 Universidad de Zaragoza 2010 Bibliografía y referencias 110-2-

PRESENTACIÓN DE LOS PATRONES DE DISEÑO Contextualización En general se han venido estudiando de forma separada Ingeniería del Software y Diseño de Algoritmos y Programación. En Ingeniería del Software se suelen analizar los diferentes ciclos de vida de construcción del software (cascada, espiral, prototipado, etc), metodología de construcción, explotación y calidad del software (métrica, ISO 9000-3, etc.), y modelos de objetos (OMT, UML, etc.). En Diseño de Algoritmos y Programación se suelen aprender las estructuras de un lenguaje de programación y sus características y se implementan en ese lenguaje problemas de diferente índole. Los Patrones de Diseño actúan como puente entre estas dos materias (Ingeniería del Software y Diseño de Algoritmos y Programación). En palabras de Donald Knuth, First create a solution using sound software engineering techniques, then if needed, introduce small violations of good software engineering pinciples for efficiency s sake, es decir Primero crear una solución usando técnicas de ingeniería del software conocidas, luego si es necesario, introducir pequeños camios de los principios de ingeniería del software bien establecidos por razones de eficiencia. Programación Estructurada VS Programación Orientada a Objetos (POO) Programación Estructurada: o Hace unos diez años que cayó en desuso pero todavía se sigue usando sobre todo en aplicaciones legadas (legacy). o Comprende fundamentalmente tres fases: Análisis o captura de requisitos, donde de estudia el problema y se definen las características que debe tener la solución. Diseño, donde se construye el algoritmo que resuelve el problema, ajustándose a las características que se han especificado en la fase de análisis, basándose en los bloques estructurales secuencia, condición e iteración. Por ejemplo mediante la técnica diagramas de flujo. Codificación o implementación, donde se traduce el diseño a un lenguaje de programación estructurado como por ejemplo Ada, Pascal, Cobol, Fortan,... En general esta traducción es bastante directa. o En general la mayoría de errores se introducen en la fase de diseño. Además cuanto más tarde se detete un error más problemas suele suponer. Debido a esto se dedica mucho tiempo a esta fase para tratar de evitar errores tempranos. o Supone que los requisitos permanecen inalterados durante todo el ciclo de vida y que se conocen de antemano, de modo que cambios o nuevos requisitos según Horowitz en 1993 suponen un 70% del coste total en mantenimiento. o Debido a esto se introdujo el ciclo de vida de desarrollo del software en Espiral y el Prototipado en lugar de emplear el desarrollo en Cascada o Cascada con realimentación. Cascada y Cascada con realimentación: Fundamentalmente el ciclo de vida del desarrollo del software se realiza en bloques. Por lo tanto, en general, es necesario haber finalizado completamente cada una de las fases antes de pasar a la siguiente. Espiral y Prototipado. En general el ciclo de vida del desarrollo del software es incremental de modo que se van aumentando poco a poco las funcionalidades del sistema. En este tipo de desarrollos existe gran interacción con el usuario con el fin de disminuir los riesgos. o Separación del modelo de datos (en general especificado mediante diagramas Entidad-Relación o mediante ficheros) del modelo de procesos (en general especificado mediante diagramas de flujo). No se encapsulan las operaciones que se pueden realizar sobre los datos. Cambios en uno de ellos pueden provocar fallos en el otro porque no se manejan de forma integrada. Programación Orientada a Objetos (POO): -3- -4-

o Hoy en día es la más usada aunque en ciertas áreas como por ejemplo, implementación de algoritmos de cálculo numérico con gran carga de operaciones, todavía se siguen empleando lenguajes estructurados como Fortran. o Se basa en la suposición de que los objetos del dominio de negocio en el que se está trabajando son las entidades más estables del sistema de modo que cualquier diseño basado en estos objetos será más resistente a los cambios en las especificaciones que puedan darse posteriormente. o Fusiona el/los modelos de datos y los modelos de proceso en clases de objetos. Cada clase lleva incorporados los datos que requiere mediante un conjunto de atributos que representan sus características y los procesos necesarios para manipularlos mediante un conjunto de métodos que representan su comportamiento. Además como ventaja adicional reduce el vacío entre el software y los modelos de negocio, de modo que un modelo de objetos o diagrama de interacción puede ser fácilmente comprensible por un empresario. o Las fases en el proceso de desarrollo del software son las mismas pero los objetivos, métodos y técnicas de cada una de ellas difieren enormemente: Análisis o captura de requisitos: al igual que en el la programación estructurada, en esta fase, se estudia el problema y se definen las características (requisitos) que debe tener la solución. La diferencia radica en que en este caso el análisis se centra en el dominio de estudio y tiene como objetivo construir un modelo del mundo real empleando objetos. Dicho modelo suele expresarse mediante el modelo conceptual (diagrama de clases que resuelve el problema pero no representa una descripción de los componentes software) y diagramas de UML como por ejemplo los casos de uso. (Fase de investigación) Diseño, el objetivo de esta fase es crear es refinar los modelos obtenidos en el análisis de modo que se enriquezcan con suficientes detalles próximos a la implementación. Debido a esto en esta fase es necesario comprobar que se cumplen los requisitos y asignar responsabilidades e interacciones entre objetos. En esta fase se suelen usar los diagramas de clases (extienden el modelo conceptual de la fase de análisis enriqueciéndolo con atributos métodos y relaciones de interacción), colaboración, estado y ciclos de vida de UML. (Fase de búsqueda de solución lógica) Codificación o implementación, al igual que en la programación estructurada, en esta fase, se traduce el diseño elaborado a un lenguaje de programación. El lenguaje seleccionado suele ser un lenguaje orientado a objetos como por ejemplo Java, C++, C# o cualquier otro de la familia.net, SmallTalk, etc.; aunque podría ser otro tipo de lenguaje, como por ejemplo un lenguaje estructurado o un lenguaje funcional (Caml, Erlang, etc.). o Problemas que se deben afrontar: Se debe buscar un diseño reusable y suficientemente flexible a cambios y ampliaciones (escable) a la vez que eficiente. Cuáles son las clases y objetos que deben intervenir y qué responsabilidad se le asigna a cada uno de ellos? Cuál es la granularidad correcta para las clases? Cuándo usar la herencia de clases y cuándo usar la implementación de una interfaz? Cómo deben interactuar los objetos?, es decir, cómo intercambian mensajes (o peticiones, request) entre ellos para realizar sus funciones (o responsabilidades)? o Cuáles son las relaciones entre ellos? o En la metodología orientada a objetos sigue habiendo problemas fundamentalmente por dos razones: En algunos modelos de diseño existe un uso inadecuado de la encapsulación de modo que hay una visibilidad de atributos y métodos incorrecta. Esto suele provocar mayor acoplamiento entre clases del debido, de modo que cambios en una de ellas implica cambios en las demás, es decir mayor dificultad de mantenimiento. -5- -6-

En muchos casos existe un vacío entre el análisis y el diseño y entre el diseño y la implementación. Esto provoca que los modelos proporcionados en la fase de diseño no sean buenos. Fundamentalmente se dan dos problemas; o bien no se han refinado suficientemente el modelo de modo que el programador debe tomar decisiones de diseño sin tener suficientes conocimientos del dominio; o bien existe una sobreespecificación de modo que no se proporciona suficente libertar al programador (p.e. especificándole una estructura de datos concreta en donde implementar una lista). Por qué debemos conocer los patrones de diseño? Los diseñadores expertos saben que no se debe empezar a resolver todos los problemas desde el principio. Además también conocen diversas soluciones ya probadas que le evitan reinventar la rueda. En general Los diseñadores senior normalmente reusan soluciones que ya han trabajado anteriormente y que les han proporcionado buenos resultados. La idea de los patrones de diseño es especificar soluciones buenas y determinar sus características de algún modo para que puedan ser integradas en los diseños de aplicaciones incluso por diseñadores no expertos. Es decir capturar la experiencia para poder usarla eficientemente. Esta idea aplicada hoy al software surgió de la arquitectura: o Christopher Alexander Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. o Christopher Alexander. A Pattern Language: Towns, Buildings, Construction, 1977. The Timeless Way of Building, 1979. Qué es un patrón de diseño? Víctor Gulías Nuevo collar para un perro viejo: Abstracción, es decir, dada una solución a un problema específico se trata de determinar cuál es la esencia de la solución eliminando la parte específica del contexto, de modo que dicha esencia pueda ser usada para resolver problemas en contextos diferentes. De este modo se permite el reuso de ideas (diseños) no sólo código. Definición 1: Es una solución de diseño válida en diferentes contextos y que ha sido aplicada con éxito en el pasado(al menos una vez), la cual se cataloga de modo que pueda ser aplicada en el futuro para resolver nuevos problemas con la misma esencia. O lo que es lo mismo, es una solución de diseño a un problema no trivial efectiva y reusable (se puede aplicar a un abanico de problemas de diseño en distintas circunstancia). Cómo se cataloga (describe) un patrón de diseño? o Nombre del patrón: Describe un problema de diseño, su solución y las consecuencias en una o dos palabras. En general se suele especificar en castellano y en inglés. o Clasificación (campo opcional): Indica de que tipo es el patrón. o Propósito: Indica en dos o tres líneas cuál es el problema que intenta resolver el patrón y su propósito. o Otros nombres (Also Known As) (campo opcional): Si existen otros nombres con los que es conocido en la comunidad deberían especificarse. o Motivación: Describe un ejemplo real de problema (el escenario) que ha sido resuelto con el patrón, especificando la estructura que lo resuelve (la solución). El escenario ayudará a entender la descripción más abstracta que se indicará a continuación. o Aplicabilidad: Especifica cuáles son las situaciones donde se puede usar. Además da ejemplos de cómo puede solucionar problemas de diseños pobres y cómo se pueden reconocer esas situaciones. o Estructura: Especifica mediante notaciones gráficas (diagrama de clases, colaboración y estado fundamentalmente) cuál es la solución al problema de forma abstracta. Esta notación es sumamente importante pero no es suficiente porque sólo captura el producto final del proceso de diseño. Para poder reusar un patrón es necesario también recordar las decisiones, alternativas y ventajas e inconvenientes a las que nos dirigen además de ejemplos que nos puedan ayudar. -7- -8-

o Participantes: Lista las clases y objetos que intervienen en la estructura del patrón y especifica cuál es la responsabilidad de cada uno de ellos. o Colaboraciones entre participantes: Indica cómo interaccionan los diferentes participantes (clases y objetos) que intervienen en su estructura. o Consecuencias: Describe las ventajas e inconvenientes de la aplicación del patrón. Además se indica cómo soporta los objetivos y qué aspectos del sistema pueden variar. o Implementación: Técnicas y peligros que conlleva la implementación del patrón. o Código de ejemplo: Solución limitada que puede servir de base para implementaciones que usen el patrón. o Usos conocidos (campo opcional): Ejemplos de uso del patrón en sistemas reales. o Patrones relacionados (campo opcional): Listado de patrones relacionados incidiendo en las diferencias de uso y en el posible uso conjunto de estos, es decir con qué patrones debería usarse. Consecuencias del uso de patrones de diseño Los patrones guardan experiencias de diseño orientado a objetos. Además nombran, evalúan y explican diseños que se repiten a menudo en los sistemas orientados a objetos. Facilitan el aprendizaje de diseñadores junior, y permiten ahorro de tiempo en la elaboración de diseños puesto que la toma de decisiones es automática; debido a que ayudan a escoger alternativas de diseño. Ámbito de li ió o El propósito, el cual trata de reflejar lo que hace el patrón. Los patrones pueden ser: De creación: El próposito del patrón es crear nuevos objetos de forma transparente al sistema. Estructurales: Reflejan la composición formada por diferentes objetos o clases con un objetivo establecido formando una estructura mayor. Nos indican cómo estructurar en memoria los objetos que intervienen en el problema. De comportamiento: Reflejan la forma de interactuar diferentes objetos o clases distribuyendo su responsabilidad para lograr un objetivo establecido. o El ámbito de aplicación, el cual trata de reflejar a que tipo de elementos se aplica el patrón. Si se trata de relaciones entre clases estas pueden ser establecidas en tiempo de compilación, mientras que si se trata de relaciones entre objetos que pueden cambiarse de forma dinámica estas tienen que ser establecidas en tiempo de ejecución. Clasificación de los Propósito patrones de diseño más conocidos Creación Estructural Comportamiento Interpreter o Intérprete Factory Method Adapter o Clases o Factoría Adaptador Template Method o Plantilla Facilitan la comunicación entre diseñadores debido a que establecen un marco de referencia de terminología y justificación, puesto que son conocidas las clases que intervienen en ellos y las interacciones entre los objetos. Mejoran la documentación y el mantenimiento de las aplicaciones. Clasificación de patrones de diseño Se realiza una clasificación en base a dos criterios: -9- -10-

apliación Objetos Abstract Factory o Fábrica Abstracta Builder o Puente Prototype o Prototipo Singleton o Instancia única Adapter o Adaptador Bridge o Puente Composite o Composición Decorator o Decorador Facade o Fachada Flyweight o Objeto ligero Proxy Chain of Responsability o Cadena de responsabilidad Command o Comando Iterator o Iterador Mediator o Mediador Memento o Recuerdo Observer o Observador State o Estado Strategy o Estrategia Visitor o Visitante Todos los patrones aquí enumerados han sido ampliamente probados y empleados en diferentes sistemas. Además no pertenecen a ningún dominio específico sino que resuelven problemas genéricos. Algunos de los patrones aquí descritos han sido incorporados como estructuras de lenguajes del programación como por ejemplo el patrón observador en el lenguaje SmallTalk o el patrón Iterador en el lenguaje Java. PATRONES ESTRUCTURALES Patrón Composite o Composición Clasificación: Estructural, debido a que nos indica cómo se organizan los objetos en memoria para obtener una composición recursiva o lo que es lo mismo una jerarquía en forma de árbol. Propósito: Construir una jerarquía compuesta por dos tipos de objetos: primitivos (nodos hoja) y compuestos (nodos internos). Los objetos compuestos permiten componer objetos primitivos y otros objetos compuestos en estructuras arbitrariamente complejas. A este tipo de jerarquías también se le suele llamar composiciones recursivas y jerarquías parte-todo. El patrón permite a los clientes de los objetos composición tratar de forma uniforme a los objetos primitivos y a las composiciones, es decir trata de igual forma a los nodos hoja como a los árboles o nodos internos. Motivación: Diseño de un editor gráfico en dónde es posible construir objetos complejos a partir de otros más simples. El cliente que usa esta jerarquía de objetos complejos (en este caso el Editor) está interesado en tratar de forma uniforme a los objetos primitivos y a los compuesto para simplificar su código. Objetivos del taller Identificar las características fundamentales de los patrones más conocidos y determinar cuándo se deben aplicar. Reproducir y modificar aplicaciones sencillas en las que se aplican patrones de diseño codificados en lenguaje Java. Requisitos Conocimientos previos: Orientación a objetos y UML. Software: Java 1.5. o El método draw() en la clase Graphic es un método abstracto, por lo tanto se declara su signatura pero no el código que lo implementa. De este modo se obliga a tener una implementación de este método en cada -11- -12-

una de las subclases. Este método se emplea para tener una interfaz común disponible para el editor de modo que pueda dibujar cualquier objeto. Estructura (Generalización del problema para aplicarlo a diferentes ámbitos): o La clase Graphic será una clase abstracta porque tiene al menos un método abstracto. o Para los demás métodos de la clase Graphic (los que realizan el tratamiento de los hijos) se proporciona una implementación por defecto: Implementación que no hace nada (se ignora) Proporciona una excepción notificando que la operación no es válida si se hace por un nodo hoja (puesto que estos la heredan y no la redefinen) Los componentes compuestos redefinen estas operaciones. Estos métodos no pueden ser abstractos porque de ese modo los nodos hoja no tendrían implementación de ellos (en cualquier caso no la tienen que tener). Por otro lado es necesario poner estos métodos en la superclase porque sino el Cliente tendría que conocer que existen dos tipos de componentes (primitivos y compuestos). o La flecha etiquetada con graphics representa la navegabilidad, es decir el acceso va a ser siempre del objeto compuesto hacia los hijos de éste. Depende del programador como se realice la implementación de esta navegabilidad. o Debido a que el rombo está pintado de negro (agregación en UML) es responsabilidad de la clase Picture borrar todas las instancias hijas si esta se elimina. Si se duda si el rombo debe estar rellenado o no mejor dejarlo sin pintar. o Las notas son sugerencias de cómo codificar los métodos cuando se realice la programción del diseño. Aplicabilidad: o Representar composición recursiva jerárquica, es decir jerarquías todoparte. o Ignorar las diferencias en el tratamiento de objetos primitivos (individuales) y objetos compuestos (composiciones) Participantes: o Component o Componente (Graphic en el ejemplo motivador): Representa el interfaz que se les presenta a los clientes y en general se va a tratar de una clase abstracta. Declara la interfaz común para los objetos de la composición (los objetos hojas y los compuestos). Declara la interfaz para regular la composición, es decir acceder y manipular los componentes hijos. Se suelen dar al menos las tres operaciones de este tipo que se mencionan en la estructura (añadir componente, borrar componente y obtener hijo). Implementa el comportamiento por defecto para los diferentes componentes. o Leaf o Hoja (Rectangle, Line, Text en el ejemplo motivador): Representa un objeto primitivo, es decir un objeto hoja (sin hijos). Define el comportamiento de los objetos primitivos (básicos) de la composición. -13- -14-

o Composite o Composición (Picture en el ejemplo motivador): Representa un objeto compuesto, es decir el nodo raíz del árbol o un nodo interno. Define el comportamiento de los objetos compuestos, es decir de los componentes con hijos. Este tipo de operaciones (operation()) en este tipo de clases en general se definen mediante delegación en los componentes hijos. Es decir, en general las operaciones de las hojas se definen aquí por delegación en los hijos. Almacena los componentes hijos. Implementa las operaciones relacionadas con los hijos de la interfaz componente. Estas operaciones son las que van a regular la asociación. o Client o Cliente: Maneja los objetos de la composición a través de la interfaz común Componente, es decir sólo tiene conocimientos de la superclase de la jerarquía de clases.. Colaboraciones entre participantes: o El cliente emplea la interfaz Componente (el API que actúa como superclase) para interactuar con los objetos de la composición: Si se actúa sobre una hoja, entonces la petición es realizada directamente por la instancia correspondiente. Si se actúa sobre una composición, en general s eredirige la petición del compoenente a sus hijos y se realiza alguna acción adicional (posiblemente antes o después de rediriguirle la petición). Consecuencias (ventajas e inconvenientes): o Ventaja 1: Simplifica el cliente debido a que trata a los objetos compuestos y primitivos de forma uniforme. El cliente no conoce, ni debería saber con lo que está tratando. Esto simplifica el código del cliente porque evita tener que escribir funciones con sentencias condicionales (if, case, selects, etc.) para las clases de la composición. o Ventaja 2: Facilita la introducción de nuevos componentes sin afectar al cliente. o Desventaja: Resulta complejo restringir los componenetees de un objeto compuesto, y para ello normalmente es necesario añadir comprobaciones en tiempo de ejecución. Por ejemplo: Imaginar que la figura compuesta tiene que estar compuesta por un conjunto de figuras elementales todas del mismo tipo. En este caso no es viable una comprobación en tiempo de compilación y habría que llevarla a cabo en tiempo de ejecución. Implementación: (Variantes del patrón y problemas que pudede desarrollar) o Referencias explícitas al padre, es decir qué pasa si a partir de los hijos nos interesa llegar al padre?: Definir una interfaz para acceder al padre de un componente en la estructura recursiva e implementarlo de la forma apropiada. Varias posibilidades: Obtener la navegación bidireccional en la relación children o hijos. Por ejemplo si a partir de un fichero queremos saber cuál es su directorio padre.si es que tiene alguno. Una opción sería poner un atributo padre en la clase Fichero (Componente) y además añadir ahí un método obtenerpadre() que nos devuelve un Directorio. El padre necesitaría actualizarse en tiempo de ejecución al hacerse llamadas al método addchild y removechild. Esto tiene un efecto desagradable en el API y es que le damos al cliente una referencia a la clase directorio y en principio el cliente no debería saber que existen dos tipos de ficheros diferentes. Establecer una relación recursiva de Fichero consigo mismo de cardinalidad (0..1) de modo que se evite que el cliente tenga que conocer la estructura de directorios. El problema aquí es que no se está representando lo mismo y así un componente compuesto podría ser hijo de un componente primitivo. Debido a esto tenemos que reforzar el modelo para evitarlo. El refuerzo del -15- -16-

modelo se consigue mediante restricciones que tendrán que ser comprobadas en tiempo de ejecución: o En general el padre debe ser un objeto compuesto (Directorio), para evitar que un nodo hoja (fichero normal) sea el padre de otro nodo (fichero normal o directorio). o El padre de un objeto debe tener como uno de sus hijos al objeto. La forma más sencilla de conseguir esta restricción es cambiar sólo el padre de un objeto cuando este siendo añadido o borrado a una composición. o Compartición de componentes: Cuándo se trabaja con objetos muy pesado que no poseen estado puede interesarnos compartirlos de modo que la representación incial en árbol deja de serlo porque se produce una compartición de nodos. La representación de árbol pasa a ser la de un grafo dirigido acíclico. Por ejemplo si trabajamos con ficheros muy grandes y queremos tenerlos accesibles desde diferentes puntos podremos crear accesos directos a estos evitando duplicarlos. composición es que el cliente no sea consciente de qué objetos hojas y compuestos se están usando. Para lograrlo la clase componente tiene que definir tantas operaciones comunes para la composición y las hojas como sea posible. En general la interfaz proporciona implementaciones por defecto que se reescribirán en la subclase. Este objetivo a veces entra en conflicto con el principio de diseño de la jerarquía de clases que indica que una clase sólo debería definir operaciones que son significativas a sus subclases, y en este caso hay operaciones necesarias para los componentes que no tienen sentido para las subclases. Además crea un conflicto de seguridad porque los clientes pueden tratar de hacer operaciones poco significativas para las hojas. Cómo puede la clase componente proporcionar una implementación por defecto para ellas? Es necesario ser creativos, por ejemplo, la interfaz para acceder a los hijos es fundamental para los objetos compuestos pero no es necesaria para los objetos hoja. Sin embargo si vemos la hoja como un componenete que tienes hijos podemos definir una operación por defecto para el acceso a los hijos en la superclase donde no se devuelve ningún hijo. Las hojas usarán la implementación por defecto y la clase compuesta la refinará. o Declaración de métodos para la manipulación de los hijos: Se proporciona una implementación por defecto: Implementación que no hace nada (se ignora) En este caso hay que tener cuidado con la implementación de las operaciones pues por ejemplo la operación de obtener tamaño tal y como la habíamos planteado inicialmente aquí nos daría como resultado para el directorio Raiz 1300 bytes y esto no es correcto. Este tipo de implementaciones todavía se complicaría más si quisiésemos tener la navegación en los dos niveles, es decir guardar referencias a las listas de los padres. Proporciona una excepción notificando que la operación no es válida si se hace por un nodo hoja (puesto que estos la heredan y no la redefinen) Los componentes compuestos en general redefinen estas operaciones y los simples las heredan. o Lista de Componentes en Component? En algunas ocasiones se ingnora la clase Composite y se sustituye el modelado por: o Maximizar la interfaz Component (Decisión que balancea Seguridad-Transparencia): Uno de los objetivos del patrón -17- -18-

haberse modificado desde la última vez que se realizó la operación obtener tamaño. Esto incurre en una penalización de espacio para todas las hojas, porque tienen reservado el espacio para tener hijos aunque estas nunca lo usen. Esta implementación es más sencilla (hay una clase menos) pero sólo vale la pena si hay relativamente pocos nodo hoja en la estructura. Si se usa esta implementación del patrón la asociación padre encaja con mayor facilidad haciendo la asociación children bidireccional. Sin embargo se corre el peligro de que se use el espacio de los hijos en los nodo hoja para haer cualquier cosa. o Ordenación de hijos: Puede diseñarse un orden de los hijos de un objeto compuestos. Por ejemplo en el editor esto puede ser interesante para reflejar la superposición de las figuras y en el ejemplo de los ficheros para reflejar la antigüedad de los ficheros creados. Otro ejemplo en el que podría resultar de utilidad es cuando la composición refleje árboles sintácticos. La ordenación en los hijos se logra mediante una restricción (ORDER) en la asociación children o hijos. Esta restricción deberá tenerse en cuenta a la hora de realizar la implementación. o Mejora de rendimiento usando cachés en objeto Composición. En las implementaciones del patrón es común usar una caché a nivel del objeto compuesto que guarde información acerca de los hijos. Por ejemplo cuando estamos tratando de obtener el tamaño de un directorio que contiene otros directorios, si realizamos la operación tal y como la hemos implementado se llama siempre a las operaciones de todos los descendientes a pesar de que alguna parte de la estructura puede no El uso de las cachés lleva asociado el problema de su actualización. Cambios en los componentes hijos requeiren la invalidación de las cachés de sus padres. De modo que este tipo de implementaciones funcionará mejor cuando existen referencias a los padres. o Responsabilidad de borrado. En general cuando no existe recolector de basura lo más sencillo es hacer responsable del borrado de los hijos al objeto compuesto que los contiene de modo que si se borra el objeto compuesto este debe eliminar los hijos. Una excepción a esta regla se produce cuando los objetos hijos pueden ser compartidos por varios objetos compuestos. En Java, como tiene recolector de basura, si se elimina un fichero de un objeto directorio simplemente bastará con romper la asociación y el recolector de basura liberará la memoria posteriormente del objeto eliminado de la asociación si este no está referenciado por otro objeto compuesto sin tener que programar mecanismos adicionales. o Estructura de datos para almacenar hijos: En la fase de diseño no se debe obligar a una estructura de datos concreta (listas enlazadas, arrays, árboles, tablas hash, etc. ) esa elección deberá tomarse en la implementación y dependerá de la eficiencia. Código de ejemplo y ejercicios: o Ejercicio 1: Obtener una representación de los árboles de directorios y los ficheros que estos contienen permitiéndonos conocer el tamaño que ocupan en disco. Recordad que en muchos lenguajes los directorios se tratan como ficheros. (Pista: Fichero, FicheroNormal y Directorio). o Ejercicio 2: Implementar la clase Cliente. El cliente debe crear la siguiente estructura de directorios: -19- -20-

La tentación directa una vez hemos definido esto es implementar cada una de las clases que aparece en el diagrama de forma independiente. Si pensamos en mayor profundidad vemos que existe código muy parecido entre por ejemplo los frames y las columnas y también entre los caracteres y las imágenes. o Documento * Página * Columna * Línea Texto * Caracter A continuación se debe mostrar por pantalla el tamaño total del fichero raíz, elimiar el directorio usr y elininar el fichero b. Finalmente se debe obtener de nuevo por pantalla el tamaño del fichero (directorio) raíz. o Ejercicio 3: Probar la clases anteriores y realizar un diagrama de secuencia indicando como fluyen los mensajes entre los objetos. y hacer un diagrama de secuencia indicando como fluyen los mensajes entre lso diferentes objetos. o Ejercicio 4: Aumentar el diseño anterior permitiendo la asociación padre. o Ejercicio 5: Pensar en la estructura de un documento en un editor de textos. Podría ser algo como lo que se indica a continuación: * * * * Frame Imagen * Pensar como se podría realizar en diseño considerando el patrón composición puesto que hay elementos que no pueden contener a otros elementos del documento mientras otros si pueden.. Patrones relacionados: Decorador, Iterador (realizar la navegación entre los hijos), Objeto ligero (para compartir componentes), cadena de responsabilidad, Visitante (localiza operaciones y comportamientos que deberían ser distribuidos a lo largo de la composición y en las clases hojas). Patrón Proxy Clasificación: Estructural, debido a que nos indica cómo se organizan los objetos en memoria. Otros nombres: subrogado o subrogate. Propósito: Proporcionar un subrrogado o intermediario de un objeto para controlar su acceso. El intermediario (o subrogado) controla el acceso al objeto que estamos considerando. Motivación: o Problema: En el contexto de un editor gráfico consideremos los objetos gráficos (imágenes) que puede haber dentro de un documento. En general no todas las imágenes van a tener que cargarse cuando se abra el documento porque depende que zona estemos visualizando hará que se muestren o no. La apertura del documento debería ser rápida y en general las imágenes suelen ser bastante pesadas, sobre todo si son de gran tamaño. o Solución: Debido a que no es necesario crear todos los objetos con imágenes nada más abrir el documento porque no todas son visibles se puede hacer carga bajo demanda. -21- -22-

La implementación de la carga bajo demanda por parte del editor hace que este se complique, además la funcionalidad de carga bajo demanda puede ser requerida por diversos módulos. Modificar la clase imagen para que esta sepa cuando tiene que cargarse en función de un estado interno tampoco parece una buena opción porque esta clase se puede usar en otras aplicaciones donde no se requiere la carga bajo demanda. Crear una copia de la clase imagen y modificarla para permitir la carga bajo demanda tampoco se considera un buen diseño porque implica tener código duplicado con todas las desventajas que esto conlleva. Para evitar complicar el editor y dar al objeto imagen responsabilidades que no le incumben (añadir funcionalidad adicional a la clase imagen), se puede emplear un objeto proxy. Este objeto se comportará como la imagen de cara al editor pero será responsable de la carga bajo demanda de la imagen. En el proxy se pude almacenar el nombre del fichero como una referencia al objeto real (suponiendo que la imagen está en disco). La clase ImageProxy cuando puede resolver las operaciones por si misma las resuelve y proporciona el resultado (por ejemplo devolver la extención o tamaño del fichero de la imagen), en caso de que se le requiera una operación que implique la carga de la imagen entonces la cargará en ese momento y delegará la operación correpondiente en el objeto imagen. Aplicabilidad: o Cuando exista una forma de referencia a un objeto más sofisticada que un simple puntero, como por ejemplo las siguientes: Proxy remoto: El proxy representa en local a un objeto remoto. Este tipo de proxies es útil en aplicaciones distribuidas. Proxy virtual: El proxy crea objetos costosos bajo demanda. El editor interactuará con el proxy, el cual delega en la imagen si no puede resolver la operación por si mismo y se encarga de realizar la carga bajo demanda. Para que el editor no tenga conocimiento de la existencia de proxies se crea una clase abstracta que propociona los métodos de la imagen al editor, actuando como interfaz. Esta clase abstracta actuará como superclase del objeto proxy y del real. Proxy de protección: El proxy controla el acceso a un determinado recurso (objeto original). Por ejemplo si disponemos de una clase en concreto, denominémosla X, puede que esta no realice la comprobación de los parámetros que llaman a sus métodos. En muchas aplicaciones esta comprobación no será necesaria pero en algunas otras puede ser requerido. -23- -24-

Estructura: No se deberían incorporar las comprobaciones a la clase porque esto la haría más pesada y en muchos casos no se necesitarían (depende del cliente). En lugar de la opción anterior el proxy puede realizar la comprobación de los parámetros. Si los parámetros son correctos el proxy delega la llamada en el objeto y sino trata el problema. Contar las veces que se accede a determinados métodos para determinar cuales son las operaciones más demandadas o tener uncontador de referencias al objeto real para controlar la concurrencia al acceder a él. Proporcioan la misma interfaz que el sujeto (Subject) para que un proxy pueda ser substituido por el sujeto real. Controla el acceso al objeto real y puede ser el responsable de su creación y borrado, por ejemplo el proxy podría decidir liberar de memoria un determinado objeto (en el ejemplo motivador la Imagen) porque no se está usando en ese momento. Ojo con esto porque puede ser que luego vuelvas a necesitar el objeto y la creación del objeto también consume tiempo. Además en función del tipo del proxy del que se trate: Es el responsable de codificar una petición y sus argumentos y enviarla al objeto remoto (Proxy Remoto) disponible en una determinada dirección. Actuá como caché de información del objeto real para evitar en la medida de lo posible el acceso a este. (Proxy Virtual o Caché). Comprueba la corrección de los permisos y/o parámetros de peticiones. (Proxy de protección). o Subject (Graphic): Define la interfaz común del Proxy y el RealSubject de modo que el proxy se pueda usar en cualquier lugar donde se espera un sujeto real. o RealSubject (Image): Define el objeto real que está siendo representado por el proxy. Participantes: o Proxy (ImageProxy): Mantiene una referencia al objeto real (RealSubject). El proxy puede referirse a Sujeto o Subject si las interfaces del Sujeto y SujetoReal o RealSubject son las mismas. Colaboraciones entre participantes: Dependiendo de la clase de proxy, el objeto proxy realizará una serie de operaciones y redirigirá peticiones al objeto real que está representando. Desde el punto de vista del cliente el proxy y el sujeto real forman un objeto compuesto en donde el proxy envuelve al objeto real. Consecuencias: o Introduce un nivel de indirección en las peticiones que requieren acceder al objeto, lo que conlleva a una pequeña penalización que en general puede permitirse. o Además dependiendo del tipo de Proxy: -25- -26-

Los proxies remotos ocultan el lugar donde residen los objetos reales. Los proxies virtuales realizan optimizaciones como por ejemplo la carga bajo demanda o cacheado de resultados para evitar diferir la operación al sujeto real. Los proxies de protección permiten realizar diversas tareas ante el acceso a un objeto como por ejemplo comprobar los parámetros o permisos. o Cuando se modifique alguna de las copias el proxy solicitará la creación de la copia al objeto real. o Se pueden usar también en copias bajo demanda (copy-on-write o creación bajo demanda), retrasando la replicación de un objeto hasta que este cambia: Crear una copia de un objeto complejo y de gran tamaño puede ser una operación cara. Además si la copia nunca se modifica no hay necesidad de realizar ese gasto, usando un proxy se puede posponer el proceso de copia hasta que sea requerido un cambio en la copia. Para copiar bajo demanda es necesario que el objeto real tenga un contador. La copia del objeto (solicitada a través del proxy) no hará nada más que incrementar ese contador de referencias. Solamente cuando se requiera un cambio el proxy hace una copia y el contador se decrementa. Además cuando la referencia es cero el sujeto real se borra. o Inicialmente la situación es esta: o Problemas de esto: Es necesario que el proxy sepa que métodos modifican el estado del sujeto real y también es necesario introducir un contador en el sujeto real. Implementación: o Los proxies no siempre necesitan conocer el tipo del sujeto real con el que están trabajando. Si una clase proxy puede tratar con el sujeto real sólo conociendo una interfaz abstracta entonces no hay necesidad de que lo conozca y para instanciar el objeto real pueden emplear una factoría si esta está disponible. o Es necesario que los proxies tengan algún mecanismo para referenciar cuál es el objeto real que les corresponde antes de instanciarlo. Patrones relacionados: o Cuando se solicita una copia la acción será crear un nuevo proxy sobre el mismo sujeto real: o Adaptador o Adapter: Un adaptador proporciona diferente interfaz al del sujeto real (el objeto que adapta). En contraste un rpoxy proporciona la misma interfaz que el sujeto real. Sin embargo un proxy usado para la protección de acceso pudiera no logra una operación que el sujeto si logra por lo tanto su funcionalidad puede ser efectivamente un subconjunto de la funcionalidad del objeto real. -27- -28-

o Decorador o decorator: Aunque pueden tener implementaciones similares a los proxies tiene diferente propósito. Un decorador añade más responsabilidades al objeto en tiempo de ejecución mientras que un proxy controla el acceso a él. En cualquier caso variantes del patrón proxy son implementadas como decoradores como por ejemplo un proxy de protección con varios niveles de control. Por otro lado los proxies remotos y virtuales mantienen una referencia indirecta al sujeto real (como por ejemplo la dirección del servicio o el nombre de la imagen) y los decoradores mantienen una referencia directa. Código de ejemplo: o Ejercicio1: Probar el código proporcionado que simula el comportamiento del patrón y elaborar un diagrama de clases con su estructura. De qué tipo de proxy se trata y por qué? o Ejercico 2: Realizar un diagrama de secuencia del código proporcionado. Patrón Decorator o Decorador Clasificación: Estructural, debido a que nos indica cómo se establecen las relaciones entre los diferentes elementos en memoria. ventanas de la misma forma, posean las funcionalidades adicionales o no por lo que no es viable modificar la clase Ventana. La modificación de la clase Ventana supondría cargas adecionales para otras aplicaciones que no requieren esas funcionalidades. o Solución 1: La alternativa más directa para modelar este problema es usar la herencia para extender las responsabilidades de la clase Ventana y crear una subclase VentanaConScroll, otra VentanaActiva y otra ventanaactivaconscroll. Esta solución es bastante ineficiente porque se produce una explosión de clases a medida que se quieran proporcionar nuevas funcionalidades. Esta solución también es inflexible puesto que es estática y un objeto es difícil que puede transformarse de una clase a otra dinámicamente (en tiempo de ejecución); es decir, es una sólución estática hecha en tiempo de compilación. Esta solución provoca herencia múltiple que en determinados lenguajes de programación puede ser difícil de implementar. Otros nombres: wrapper. Propósito: Añadir responsabilidades o características a un objeto en concreto dinámicamente, proporcionando una alternativa flexible a la extensión de una clase para aumentar la funcionalidad. Motivación: o Problema: En el contexto de un editor de texto consideremos las ventanas gráficas que muestran el documento. Se desea que las ventanas donde se muestra el documento puedan proporcionar un borde que estará activo cuando se esté trabajando sobre esa ventana y una barra de desplazamiento o scroll si el documento es de un tamaño considerable. Se desea añadir esa responsabilidad a objetos en concreto no a una clase. Además se pretende que estos dos funcionalidades adicionales no supongan modificar el cliente, es decir que los clientes traten las o Solución 2: Debido a los problemas que supone la creación de nuevas subclases se opta por encapsular el objeto base (ventana o TextView) dentro de otro objeto que añade las nuevas funcionalidades (objeto decorador). Además como no se desea que el cliente diferencie entre -29- -30-

objetos sin decorar y decorados se considera una interfaz común (visualcomponent). El decorador redirige las peticiones al objeto base y añade las nuevas funcionalidades antes o después de la redirección. Pueden existir diferentes tipos de funcionalidades que se desean añadir (en el ejemplo motivador en concreto son dos: Scroll y borde activo) por ello se considera una interfaz (Decorador) que las engloba a todas y que actúa como mecanismo encapsulador. Esta interfaz puede especializarse proporcionando el comportamiento de las diferentes funcionalidades. añadir nuevas funcionalidades que no están disponibles en el objeto sin decorar (scroolto, drawborder). Los clientes de los componentes visuales no hacen distinción entre los componentes decorados y sin decorar. Aplicabilidad: o Añadir ó eliminar responsabilidades de objetos de forma dinámica y transparente, sobre todo cuando no es práctico el uso de la herencia debido a su inflexibilidad y explosión de clases. Estructura: Participantes: o Componente o Component: Define la interfaz para que el cliente trate de forma uniforme objetos decorados que objetos básicos. o ComponeneteConreto o ConcreteComponent: Define un objeto al cual se le pueden agregar responsabilidades adicionales. La superclase Decorator impelementa la interfaz del componente visual, redirigiendo los métodos al componente que encapsula. Además la transparencia de la interfaz VisualComponent permite el anidamiento de decoradores permitiendo un número no limitado de nuevas funcionalidades. Las subclases decoradoras refinan los métodos del componente añadiendo responsabilidades. Además las subclases pueden o Decorador o Decorator: Mantiene una referencia al componente encapsulado (asociado) e implementa la interfaz de la superclase Componente. El Decorador delega en el componente asociado las operaciones de la interfaz. o DecoradorConcreto o ConcreteDecorator: Añade funcionalidades (responsabilidades) al componente (refinamiento). Colaboraciones entre participantes: -31- -32-

o El decorador redirige las peticiones al componente asociado y opcionalmente puede realizar tareas adicionales antes o/y después de redirigir la petición. Consecuencias: o Es una estructura más flexible que la herencia (la cual es estática) puesto que es configurable en tiempo de ejecución y evita la herencia múltiple. Además con el decorador las responsabiliddades pueden ser añadidas o eliminadas y se evita la herencia múltiple. o Evita la aparición de clases con muchas responsabilidades en las clases superiores de la jerarquía permitiendo incorporar las responsabilidades incrementalmente. Esto tiene la ventaja añadida de que no es necesario pagar un coste por funcionalidades no requeridas. Además también es sencillo definir nuevos tipos de decoradores independientemente de las clases de objetos que extienden por ejemplo para extensiones no previstas inicialmente. o Puede provocar problemas con la identidad de los objetos. Un decorador actúa como un envoltorio transparente de un objeto componente pero desde el pundo de vista de la identidad de los objetos un componente decorado no es idéntico al componente en si mismo puesto que no tienen la misma referencia. Por lo tanto no se debería confiar en la identidad de los objetos cuando usas decoradores. Cuándo dos objetos son el mismo, cuando tienen la misma referencia o cuamdno forman parte del mismo objeto compuesto, el cual se construye sobre el mismo objeto base? Se puede plantear una solución y usar un identificador calve único (atributo id) para identificar los objetos de modo que no se emplee la referencia. Nótese que el identificador sólo lo tendría el objeto básico (TextView) y que los decoradores lo heredarían. Es decir se pondría un atributo _clave en el TextView o en Unidad y un método abstracto obtenerid(). El componente básico devuelve el nomber en obtenerid() y los decoradores delegan en el componente esa operación. o Puede provocar la existencia de un gran número de objetos pequeños y además se producen pequeñas penalizaciones por cada nivel de indirección introducido. Implementación: o El decorador debe cumplir la interfaz de la clase Componente para que el cliente no distinga entre objetos básicos y decorados. o Cuando sólo exista la posibilidad de añadir un tipo de funcionalidad a los objetos básicos se puede omitir la clase abstracta Decorador. En general esto no es así y además conviene ponerla porque proporciona mayor flexibilidad al diseño. o Se debe mantener la clase Componente o Component ligera. Así la definición de los datos de representación debería hacerse en las subclases porque sino se hará a las clases decoradoras muy pesadas para poder ser usadas de forma anidada. Además añadir demasiada funcionalidad en la interfaz Componente aumenta la probabilidad de que se pongan características que para un caso en concreto no se utilicen. o Patrón Decorador vs patrón Estrategia: En este caso se le están añadiendo nuevas pieles (Decorador) que aumentan la funcionalida al objeto base. Si en lugar de añadir funcionalidades se quisiese cambiar el medio de conseguir la funcionalidad del objeto base entonces se emplearía el patrón Estrategia. Además el patrón estrategia se debe aplicar también cuando la clase Component es demasiado pesada. En el patrón decorador el componente no tiene que saber nada de los decoradores, es decir los decoradores son transparentes al componente debido a que sólo se cambia un componente desde el exterior. En el patrón estrategia el componente en si mismo conoce sus posibles extensiones. Además tiene referencias y mantiene las correspondientes estrategias. Patrones relacionados: -33- -34-

o Adaptador: Un decorador es diferente de un adpatador en el sentido en que el decorador sólo cambia las responsabilidades del objeto, no su interfaz. Un adaptador proporciona una interfaz completamente nueva. o Composición: Un decorador puede verse como una composición degenerada con solo un componente (un hijo). Sin embargo un decorador añade responsabilidades no es una agregación de objetos como lo es la composición. o Estrategia: El decorador cambia la piel del objeto y la estrategia su modo de realizar las operaciones. Son dos alternativas diferentes de cambiar un objeto. Código de ejemplo: o Ejercicio 1: Crear un modelo e implementarlo para el siguiente escenario. Se consideran Unidades (soldados) de un juego de estrategia. Estas unidades pueden defender, atacar o moverse. Además tendrán un método descripción que nos propocionará un String con la información de las unidades (nombre y tipos de métodos que emplea). Las unidades en un principio son SoldadosRaso (es decir capacidad de ataque, defensa y movimiento 1) pero a medida que ganan experiencia pueden obtener complementos (escudos y pistolas) que le ayuden a desarrollar su misión. Por cada escudo que se adquiera la capacidad de defensa se multiplica por dos y por cada pistola la capacidad de ataque se multiplica por 2 (Pista: Fichero, FicheroNormal y Directorio). o Ejercicio 2: Implementa una clase Cliente de la estructura anterior que poseea el siguiente método: + Unidad combate(unidad atacante, Unidad defensor) De modo que si la capacidad de ataque de la unidad atacante es mayor que la capacidad de defensa de la unidad defensor, entonces el ganador del combate es el atacante (return atacante), en caso contrario el ganador del combate es el defensor (return defensor). o Ejercicio 3: Adapta el siguiente código para probar las clases anteriores: Public class Main{ Public static void main (String argv[]){ Cliente c = new Cliente(); Unidad ryan = new Soldado ( Ryan ); Unidad rambo = new Pistola( new Escudo( new Soldado( Rambo ))); System.out.prinln( Si + Rambo.obtenerNombre() + ataca a + Ryan.obtenerNombre() +, el vencedor es + c.combate(rambo, ryan).obtenernombre()); } } o Ejercicio 4: Si se desease disponer del método suprimircomplemento dónde sería más adecuado hacerlo disponible?. Analizar las siguientes opciones. Opción 1: Nueva responsabilidad en la clase Complemento: abstract class Complemento extends Unidad {... public Unidad suprime_complemento(complemento complemento) { if (complemento == this) return _sujeto; else { if (_sujeto instanceof Complemento) _sujeto = ((Complemento) _sujeto).suprime_complemento(complemento); return this; } }... } Unidad p = new Escudo( new Soldado("mi_unidad") ); -35- -36-

Unidad mi_unidad = new Pistola(p); mi_unidad = ((Complemento) mi_unidad).suprime_complemento((complemento) p); Opción 2: Tratamiento uniforme de Unidades y Complementos: abstract class Unidad {... public Unidad suprime_complemento(unidad complemento) { return this; }... } abstract class Complemento extends Unidad {... public Unidad suprime_complemento(unidad complemento) { if (complemento == this) return _sujeto; else { _sujeto = _sujeto.suprime_complemento(complemento); return this; } }... } Unidad p = new Escudo( new Soldado("mi_unidad") ); Unidad mi_unidad = new Pistola(p); mi_unidad = mi_unidad.suprime_complemento(p); o Ejercicio 5: Si se desease pasar como parámetro un identificador del tipo de complemento que se desea suprimir al método suprimircomplemento cómo habría que modificar la implementación anterior?. abstract class Unidad {... public Unidad suprime_complemento(string cual) { return this; }... } abstract class Complemento extends Unidad {... protected abstract String tipo(); public Unidad suprime_complemento(string cual) { if (tipo().equals(cual)) return _sujeto; else { _sujeto = _sujeto.suprime_complemento(cual); return this; }... } class Escudo extends Complemento {... protected String tipo() { return "ESCUDO"; }... } class Pistola extends Complemento {... protected String tipo() { return "PISTOLA"; }... } Unidad mi_unidad = new Pistola(new Escudo(new Soldado("mi_unidad"))); mi_unidad = mi_unidad.suprime_complemento("escudo"); Nota: En ocasiones nos puede interesar tener identificado el complemento que se manipula por ejemplo para borrarlo. Por ejemplo si una Unidad dispone de dos pistolas igual nos interesa -37- -38-

eliminar la que adquirió en primer lugar y no una cualquiera de ellas (como lo hace el método anterior.). En este caso en el constructor del complemento será necesario indicar un identificador. Patrón Facade o Fachada Clasificación: Estructural. Propósito: Proporcionar una interfaz única para un conjunto de interfaces en un subsistema. El objetivo es definir la interfaz de nivel más alto de las operaciones que realiza el subsistema para que sea más sencillo el usarlo por otros módulos o subsistemas diferentes, es decir facilitar el acceso. Motivación: o En general la división de un sistema complejo en subsistemas facilita el poder abordar el problema y reduce la complejidad. o El objetivo que se persigue es minimizar las comunicaciones y puntos de acceso de un subsistema a otro de modo que la dependencia entre subsistemas se reduzca. Es decir, disminuir el acoplamiento entre sistemas. o Solución 2: Usar el compilador como una caja negra de modo que los cambios en la estructura del compilador o sus interfaces internas no afecten, es decir no se propaguen más allá del punto de conexión que se proporciona que será la fachada. o Problema: En el contexto del desarrollo de un entorno de programación integrado por ejemplo para el lenguaje C++; se desea disponer de una herramienta debuger por lo que se requerirá hacer uso de un compilador. o Solución 1: Conocer los diferentes módulos y componentes del compilador (Scanner, Parser, etc.) de modo que pueda hacer llamadas a cada uno de ellos. o Así se reducen las dependencias entre los módulos y se aisla a los posibles clientes de los cambios internos del módulo. Sin embargo el emplear una fachada no impide que existan aplicaciones especializadas que puedan acceder a las clases del módulo directamente, es decir la fachada no oculta las funcionalidades de más bajo nivel. Aplicabilidad: -39- -40-