pLinker: Relaciones con Patrones de Diseño Leonardo Liebener1,2, Marcos Andrés Rossi1,2 and Claudia Marcos1 1 ISISTAN Research Institute, Facultad de Ciencias Exactas, UNICEN Paraje Arroyo Seco, B7001BBO Tandil, Argentina Tel/Fax: + 54–2293–440362/3 http://www.exa.unicen.edu.ar/~isistan/ E-mail: [lliebner, mrossi, cmarcos]@exa.unicen.edu.ar 2 TELPIN Cooperativa Telefónica de Pinamar Jason 1026, B7167ACT Pinamar, Argentina Tel: + 54-2254-483000 Fax: + 54-2254-482024 http://www.telpin.com.ar/sistemas E-mail: [lliebener, mrossi]@telpin.com.ar Resumen. Los patrones de diseño se han convertido en una técnica importante para el reuso de conocimiento de software. Cada patrón provee información sobre su diseño, describiendo las clases, métodos y relaciones que resuelven un problema de diseño en particular. Sin embargo, su documentación no brinda información sobre la integración de los mismos en un diseño existente, simplemente describen de manera poco detallada los patrones con los cuales esta relacionado. Este trabajo, presenta una clasificación de las relaciones entre patrones y cómo la estructura de clases de un diseño existente se ve afectada al incorporar un nuevo patrón. Con el objetivo de asistir al usuario en la construcción de diseños utilizando patrones y sus relaciones, se implementó pLinker. Dicha herramienta permite construir diagramas de clase UML e incorporar patrones en ellos. Palabras claves: Patrones de diseño, Arquitecturas de software, Desarrollo de software OO. 1. Introducción Los patrones de diseño se han convertido en una técnica popular para el reuso de conocimiento de diseño de software. La motivación principal de los patrones de diseño la constituye el hecho de encontrar frecuentemente, en diferentes diseños, problemas similares. Los patrones de diseño de software son patrones de organización de jerarquías de clases, protocolos y distribución de responsabilidades entre clases que caracterizan construcciones elementales del diseño orientado a objetos. Es decir, un patrón es una estructura de clases que aparece repetidamente en diversos diseños orientados a objetos, la cuál es utilizada para resolver un problema determinado de forma flexible y adaptable dinámicamente. El propósito de un patrón de diseño es capturar el conocimiento de un diseño de software y hacerlo reusable. Los patrones han sido agrupados y organizados en catálogos ([BMRS+96], [GHJV95], [Grand98]), cada uno dando diferentes clasificaciones y descripciones. Algunos catálogos describen patrones de análisis mientras que otros patrones de diseño, incluyendo también patrones de un dominio particular, o bien, independientes del dominio. El proceso de construcción de aplicaciones utilizando patrones se reduce a que, cada vez que el diseñador encuentra un problema, busca en los catálogos un patrón que lo resuelva. Si no existiera tal patrón, el diseñador debe pensar en una solución. En cambio, si existe un patrón, el diseñador puede aplicarlo en su diseño. En general, esto significa que los elementos de diseño de la descripción correspondiente al patrón deben ser mapeados e integrados con los elementos de diseño preexistente. Es decir, se deben identificar las clases, métodos y atributos de la aplicación que juegan el rol de aquellos prescritos por el patrón. Lamentablemente, los aspectos que implican integrar un patrón en un diseño parcial existente no son resueltos por la descripción de los patrones. Cada patrón provee información acerca de su propia implementación de una manera informal, pero no resuelve uno de los aspectos generales de la arquitectura de software con patrones, como es la integración de los mismos en diseños preexistentes. Es decir, no existe una guía o descripción que asista al diseñador a la hora de integrar un patrón a un diseño existente. Por otro lado, en la mayoría de los catálogos, como parte de la descripción de cada patrón, se mencionan posibles relaciones de éste con otros patrones de diseño. Estas relaciones muestran que un patrón puede complementar, de alguna manera, la funcionalidad de otro; o bien puede servir como alternativa del mismo. Así, se puede notar que si se aplica un determinado patrón quizás se lo pueda utilizar en conjunto con algún otro patrón relacionado para obtener una solución de diseño más completa. Desafortunadamente, la descripción de dichas relaciones no se encuentra documentada de la misma manera en la que se documenta un patrón de diseño. Más bien se trata de una descripción informal o poco detallada. Generalmente sólo se hace referencia al nombre del patrón que puede ser usado en conjunto con un patrón de diseño dado para mejorar o complementar su funcionalidad, pero no se describe en que manera se ve afectada la estructura de clases del primero para reflejar esta relación. Entonces, la descripción no ayuda al diseñador a integrar dos patrones relacionados para lograr una solución de diseño más completa. Esto hace dificultosa la tarea de construir un diseño de software aprovechando las relaciones entre los patrones. De manera de ayudar y asistir al diseñador en la construcción de aplicaciones con patrones de diseño, este trabajo propone una clasificación de las diferentes relaciones entre patrones. Se han analizado diferentes catálogos de patrones de diseño y definido relaciones entre ellos. Dichas relaciones han sido documentadas siguiendo un esquema de documentación similar al que es utilizado para describir patrones de diseño, lo cual facilita la comprensión y la forma de aplicación de las relaciones entre patrones. Con el objetivo de asistir al usuario en la construcción de diseños utilizando patrones y sus relaciones de manera simple, se implementó pLinker. Esta herramienta permite construir diagramas de clase UML e incorporar patrones en ellos. Una vez incorporado un patrón, la herramienta mostrará las relaciones existentes del patrón aplicado con el resto de los patrones y proveerá acciones a desarrollar, o puede desarrollar actividades automáticamente, de manera de incorporar el segundo patrón al diseño. El trabajo esta organizado de la siguiente manera. A continuación se describen las relaciones entre patrones de diseño definidas y el esquema de documentación utilizado. Sección 3 presenta la herramienta pLinker con sus características y sus dos modos de trabajo mostrando cada uno de ellos por medio de un ejemplo. Por último, en la Sección 4 se presentan las conclusiones de este trabajo. 2. Relaciones entre patrones En la mayoría de los catálogos, los patrones están documentados por medio de una plantilla o ficha descriptiva. Como parte de esta ficha, cada patrón debe indicar, entre otras cosas, sus relaciones con otros patrones. Pero, desafortunadamente estas relaciones se encuentran descriptas muy brevemente y además, los diferentes catálogos de patrones describen distintas relaciones de diferentes maneras. Es decir, cada catálogo o libro de patrones de diseño, describe a las relaciones entre los patrones usando su propia clasificación idiomática de esas relaciones. Por ejemplo, las relaciones en [GHJV95] son descriptas de manera informal, usando el lenguaje natural. Generalmente sólo se hace referencia al nombre del patrón que puede ser usado en conjunto con un patrón de diseño dado para mejorar o complementar su funcionalidad, pero no se describe en que manera se ve afectada la estructura de clases del primero para reflejar esta relación. Entonces, la descripción, no ayuda al diseñador a integrar dos patrones relacionados para lograr una solución de diseño más completa. Esta inconsistencia, hace que los patrones sean difíciles de utilizar. La relación de un patrón con otro es, desde la perspectiva de este trabajo, una de las partes más importantes de la descripción de los patrones; y la inconsistencia de las descripciones hace que sea difícil, para los diseñadores, entender estas relaciones y aprovechar así las ventajas de los patrones de diseño. Se han definido y clasificado los tipos de relaciones existentes entre patrones de diseño. Esta categorización surgió luego del estudio exhaustivo de algunos de los catálogos de patrones más importantes ([GHJV95], [BMRS+96], [Grand98], [Larman98]), y tiene el propósito de ayudar al diseñador a comprender mejor las relaciones entre los patrones. En el mismo, se propone un esquema de documentación similar al que es utilizado para describir patrones de diseño, lo cuál facilita la comprensión y la forma de aplicación de las relaciones entre patrones. 1.1. Documentación de relaciones Para describir los distintos tipos de relaciones definidas se utiliza un esquema de documentación en la cuál la descripción de cada tipo de relación está organizada en diferentes secciones, descriptas a continuación. La plantilla permite que la estructura de la información sea uniforme, haciendo más simple la comprensión y posible utilización de los tipos de relaciones encontradas. Nombre de la relación: el nombre con el cuál se identifica al tipo de relación. Descripción: en esta sección se muestran los detalles del tipo de relación. Entre estos detalles se puede encontrar, una descripción del contexto de aplicación de la relación, la descripción de la funcionalidad adicional proporcionada por el segundo patrón de la relación, la categoría de los patrones involucrados, etc. Momento de aplicación: esta propiedad establece cuándo puede ser aplicada una relación dada entre dos patrones. Básicamente, una relación es aplicable antes de utilizar un patrón en el diseño preexistente (pre-aplicable), implícitamente con la aplicación del patrón (implícito), o bien, después que un patrón ha sido aplicado en el diseño del usuario (post-aplicable). Consecuencias de la aplicación: en esta sección se describen las implicancias, las ventajas y desventajas de la aplicación de la relación. Acciones a realizar sobre la estructura del patrón original: describen el objetivo que tienen las acciones a realizar sobre la estructura de clases del patrón original para reflejar su relación con el segundo patrón. Este apartado no siempre está disponible ya que depende del momento de aplicación de la relación (generalmente presente en relaciones post-aplicables). Un ejemplo de una acción podría ser: “Agregar un método llamado op1() a la clase MyClass”. Actividades a realizar luego de la aplicación de la relación: una actividad es una tarea pendiente que debe ser llevada a cabo posteriormente a la aplicación de la relación para completar el uso de la misma. Generalmente, estas actividades son expresadas en lenguaje natural. En la descripción del tipo de relación generalmente se indica cual es el objetivo, o como surgen las actividades asociadas a la relación y pueden tener asociada una prioridad que indique su grado de importancia. Vínculos entre clases: los vínculos entre clases establecen la correspondencia de las clases del segundo patrón (X) con las del primero (Y), es decir, se indica cual es el rol de cada clase del patrón Y en la estructura de clases del patrón X. Ejemplos: para finalizar con la descripción del tipo de relación es importante mostrar ejemplos con patrones de diseños reales, que ayude a la identificación y comprensión del tipo de relación. 1.2. Tipos de Relaciones Se han definido seis tipos de relaciones entre patrones de diseño, las cuales son descriptas brevemente a continuación: X es alternativa de Y: este tipo de relación se establece entre dos patrones que proponen dos soluciones mutuamente excluyentes a un problema de diseño. Es decir, no pueden convivir la estructura de ambos patrones en un diseño para resolver un determinado problema. X especializa a Y: es una relación unidireccional que se establece entre dos patrones que poseen la misma estructura, se aplican bajo el mismo contexto y tienen una motivación similar, pero el patrón X incorpora nueva funcionalidad para soportar requerimientos adicionales o se comporta de manera diferente. Es decir, en este tipo de relación, X trata con una especialización del problema que trata Y. X crea a Y: generalmente, el primer patrón que conforma la relación (X) forma parte de la categoría de “patrones creacionales”, mientras que el patrón Y forma parte de la categoría de “patrones estructurales”. Se trata de una relación unidireccional en la que el patrón X crea una o más estructuras de clases similares a las que conforman la solución del patrón Y. X usa a Y en su solución: al construir la solución para el problema en el que se enfoca el patrón de diseño X, un subproblema es similar al problema al que apunta el patrón de diseño Y. En consecuencia, el patrón de diseño X usa al patrón de diseño Y en su solución. Esto implica, que la estructura de clases de Y utiliza una parte de la estructura de clases de X. Se trata de una relación unidireccional. X se usa en conjunto con Y: este tipo de relación es la más simple de detectar. Se puede dar entre patrones de diferentes categorías. Al combinar el patrón X con el patrón Y, se logra una solución de diseño más completa. Cuando esta relación es usada, la estructura de clases del patrón Y debe ser integrada a la estructura de clases del patrón X. X se aplica en cascada: este tipo de relación es establecida entre dos instancias de un mismo patrón de diseño. Algunos patrones pueden ser aplicados repetidamente para resolver un problema de diseño. Es decir, la estructura de diseño de un patrón es combinada con la misma estructura repetidamente, para resolver problemas de diseño más complejos. Por ejemplo la relación X se usa en conjunto con Y es documentada de la siguiente manera: Descripción: dos patrones se usan en conjunto para brindar una solución a un problema de diseño que no es resuelto directamente por ningún otro patrón. En casos simples, generalmente se puede encontrar un patrón de gran escala que resuelve un problema completo y otro patrón de menor escala que provee la solución a un subproblema. Por otro lado, en situaciones más complejas, dos patrones se combinan para producir una solución a un problema. El problema mismo y la manera en la cuál estos patrones son combinados no se encuentran explícitamente capturado en las descripciones de dichos patrones. Aquí, todo patrón puede ser considerado para usarlo en conjunto con cualquier otro patrón, para brindar una solución a un problema de gran escala que no se encuentra resuelto por ningún patrón individual. Cuando esta relación es activada, la estructura de clases del patrón Y debe ser integrada a la estructura de clases del patrón X. Consecuencias de la aplicación: las consecuencias de utilizar este tipo de relación en un diseño pueden expresarse como el resultado de aplicar el primer patrón, junto con el resultado de aplicar el segundo patrón involucrado en la relación. Las consecuencias de aplicar cada uno de los patrones involucrados en la relación en un diseño, pueden encontrarse documentadas en la ficha descriptiva del catálogo a cual pertenece cada uno de los patrones. Momento de aplicación: el momento de aplicación de esta relación es posterior (post-aplicable) al uso del patrón X. Al seleccionar el patrón X, cualquier otro patrón puede ser considerado para combinarlo con X, con el fin de proveer una estructura de solución más completa al problema que se está tratando de resolver. Acciones a realizar sobre la estructura del patrón original: las acciones que surgen con la aplicación de este tipo de relación, tendrán como objetivo la integración de la estructura de clases del patrón X con la estructura de clases del patrón Y. Actividades a realizar luego de la aplicación de la relación: aplicar esta relación significa que, además de haber utilizado el patrón X en un diseño dado, también se utilizará una o más veces el patrón Y, por lo que las actividades que surgirán serán aquellas correspondientes a la utilización de Y. Vínculos entre clases: aquí es importante definir los vínculos entre la o las clases del patrón X y las clases del patrón Y, de tal manera que cualquier modificación sobre la estructura de clases de Y se vea reflejada en el patrón X. Ejemplo: como ejemplo se pueden considerar los patrones de diseño Composite y al patrón Iterator. El patrón Composite (Figura 1) permite construir objetos complejos por medio de la composición recursiva de objetos similares. También permite que estos objetos sean tratados de manera uniforme, si hacer distinciones entre los objetos simples y los complejos. AbstractComponent * operation( ) ConcreteComponent1 ConcreteComponent2 operation( ) operation( ) ... AbstractComposite operation( ) add(AbstractComponent) remove(AbstractComonent) getChild(int) ... ConcreteComposite1 ConcreteComposite2 operation( ) add(AbstractComponent) remove(AbstractComonent) getChild(int) operation( ) add(AbstractComponent) remove(AbstractComonent) getChild(int) Figura 1: Patrón de diseño Composite El patrón Iterator (Figura 2) define una interfaz que declara métodos para el acceso secuencial de los objetos de una colección. Una clase que acceda a una colección a través de una interfaz, permanecerá independiente de la clase que implementa dicha interfaz. «interface» CollectionIF Creates iterator( ) : IteratorIF( ) ... Collection «interface» IteratorIF hasNextItem( ) : boolean getNextItem( ) : InventoryItem Fetches-objects-from Iterator Figura 2: Patrón de diseño Iterator Estos dos patrones pueden ser combinados para resolver el problema de recorrer estructuras de objetos complejos sin conocer la estructura interna de los mismos. Es decir, con la aplicación del patrón Iterator se logra independizar el recorrido del Composite de la organización interna de los objetos. En la Figura 3 se muestra la estructura de estos dos patrones combinados. Se puede ver que la clase AbstractComposite del patrón Composite, en la combinación ha asumido el rol de la clase Collection del patrón Iterator. Por lo tanto, la clase AbstractComposite deberá implementar el método iterator() que crea un iterador para recorrer la estructura interna de los objetos compuestos del patrón Composite. En realidad, por tratarse de una clase abstracta, las subclases de AbstractComposite tendrán la responsabilidad de redefinir este método. Complementariamente al estudio realizado para la identificación de relaciones entre patrones de diseño se ha aplicado el mismo concepto a patrones de diferentes niveles de abstracción. Existen patrones de mayor nivel de abstracción, conocidos comúnmente como patrones arquitectónicos, y de menor nivel de abstracción (patrones de diseño). De esta manera es posible especificar relaciones que permitan identificar y describir los patrones de diseño que se utilizan para el diseño detallado de cada uno de los componentes de la arquitectura de software. Por ejemplo, el patrón arquitectónico Model View Controller usa los patrones de diseño Observer, Strategy y Composite: el patrón Observer conecta la vista (View) al modelo (Model), el patrón Strategy permite al controlador (Controller) manejar los eventos que ocurren sobre la vista, y el patrón Composite provee una jerarquía de vistas. AbstractComponent <<Interface>> CollectionIF operation() iterator() ConcreteComponent <<Interface>> IteratorIF creates hasNextItem() : boolean getNextItem() : InvetoryItem AbstractComposite operation() add(AbstractComponent) re mo ve(AbstractComponen t) getChild (i nt) fetch e s objec ts f rom Iterator Figura 3: Resultado de combinar las estructuras de clases de los patrones Composite e Iterator Además, es posible determinar en que parte del patrón arquitectónico, o sea, en que componente arquitectónico es usado un determinado patrón de diseño. Siguiendo con el ejemplo, el patrón de diseño Composite es usado en el componente arquitectónico View. Esta información resulta útil para construir aplicaciones utilizando patrones de software de diferentes niveles de abstracción. 3. pLinker Se ha desarrollado una herramienta denominada pLinker la cual pretende que el usuario aproveche las ventajas del uso de patrones de diseño y, principalmente de las relaciones entre los mismos sin tener un conocimiento avanzado sobre el tema. pLinker consiste de un editor gráfico de clases UML que facilita la utilización y administración de patrones de diseño, permitiendo mantener y actualizar un catálogo de patrones de diseño y las relaciones entre los mismos. Por otro lado, provee mecanismos que simplifican la incorporación de patrones a diseños preexistentes, aprovechando además, las relaciones entre dichos patrones. pLinker posee dos modos de trabajo: El primer modo esta orientado a la construcción de diseños con patrones, permite modelar visualmente clases, interfaces y relaciones entre las mismas (herencia, uso, e implementación). Pero su principal característica es la posibilidad de incorporación de forma sencilla de patrones de diseño a un modelo de clases existente. Además, permite distinguir cuales fueron los patrones utilizados y ofrece opciones que ayudan a mejorar el diseño en desarrollo incorporando nuevos patrones en forma automática, valiéndose para ello de las relaciones existentes entre los patrones involucrados. El segundo modo esta destinado a mantener y actualizar el catálogo de patrones de diseño y sus relaciones. La incorporación de un nuevo patrón puede hacerse tomando como referencia la plantilla de documentación del mismo, disponible en cualquiera de los catálogos de patrones. Además, de incorporar la descripción del nuevo patrón se deben describir las relaciones del mismo con los patrones ya existentes en la herramienta y las acciones a desarrollar en cada uno de los casos. Otra característica que posee pLinker es que permite crear diseños partiendo de arquitecturas de software, organizando de esta manera las clases del modelo del usuario en componentes arquitectónicos. Esto brinda una ayuda adicional a la hora de utilizar un patrón de diseño, ya que por cada componente arquitectónico, pLinker propone los patrones de diseño que se usan más comúnmente en él. 4.1. Configuración de pLinker Por cada patrón de diseño, pLinker mantiene tres tipos de información: la descripción general, la estructura de clases que conforma el patrón, y las actividades a realizar para complementar su uso. En la descripción genera,l se deben especificar el nombre del patrón, la intención, la motivación y otros datos relevantes que ayuden al usuario a optar o no por un determinado patrón de diseño. La estructura de clases se refiere a las clases y relaciones entre ellas involucradas para resolver un problema de diseño particular Finalmente, las actividades representan un conjunto de tareas que debe realizar el usuario con el fin de completar la inserción de un patrón en su diseño. Por ejemplo, una actividad que surge generalmente es la de renombrar una clase del patrón para que su nombre represente exactamente lo que modela. Una actividad tiene un nombre (como podría ser: “Renombrar clase C”), una descripción que muestra los detalles y una prioridad que indica la importancia de la misma. Para incorporar la información correspondiente a esta relación, el usuario debe indicar cuales son los patrones involucrados, el tipo de relación y la descripción de la relación. También deben establecerse los vínculos entre las clases que permiten mantener la consistencia entre las estructuras de diseño de los patrones involucrados en la relación. Al establecer estos vínculos, pLinker creará automáticamente las acciones necesarias que permitan incorporar el segundo patrón de la relación en la estructura de clases del primero. Adicionalmente, pLinker permite almacenar información acerca de arquitecturas de software y sus componentes. Un componente arquitectónico puede estar diseñado con un conjunto de patrones de diseño. Por cada uno de estos componentes, pLinker permite establecer cuales son los patrones de diseño más frecuentemente utilizados en su diseño. La Figura 4 muestra cómo establecer una relación entre dos patrones en pLinker. En la misma se puede observar la configuración de la relación entre los patrones Composite y Decorador. A la izquierda de la pantalla de configuración se muestra las clases del patrón Composite y a la derecha las correspondientes al patrón Decorador. En el panel inferior se puede observar los vínculos establecidos entre las clases de ambos patrones para establecer la relación entre los mismos. 4.1 Construcción de aplicaciones A continuación se muestran las características principales de pLinker cuando es utilizado para la construcción de aplicaciones. Para ello se utilizará como ejemplo la construcción de un diseño que soporte la creación de diferentes juegos de tablero. Entre los juegos que se tienen en cuenta para el diseño se pueden mencionar el ajedrez, las damas, cuatro en línea, ta-te-ti, etc., por lo que se lo podría utilizar para crear juegos en los que participen muchos jugadores, o bien que existan distintos tipos de piezas, además de muchas otras características que incluyen los juegos mencionados. En cuanto a los jugadores que participan en el juego, el diseño no hace distinción entre lo que puede ser un jugador humano y otro que esté controlado por un algoritmo. La idea básica es que los jugadores involucrados, generen comandos y los apliquen al juego. El juego se encargará de verificar que dichas acciones sean válidas, actualizará su estado de acuerdo a ellos, y quedará a la espera de nuevas acciones. Una acción será, por ejemplo para un juego de ajedrez, “mover el alfil de tal lugar a tal otro”, o bien si se piensa en un juego como el reversi, “poner una ficha roja en tal celda”. Figura 4: Configuración de pLinker: Relaciones entre patrones 4.1.1. Creación de un proyecto pLinker Lo primero que se debe hacer antes de comenzar a incorporar clases y relaciones al diseño, es crear un proyecto. El proyecto será la unidad de trabajo de pLinker, y es el encargado de contener tanto el diseño de clases del usuario como las instancias de los patrones utilizados. Así mismo, organiza el diseño en componentes arquitectónicos. pLinker permite trabajar con múltiples proyectos a la vez. El primer paso para crear un proyecto es indicar la arquitectura de software a utilizar, para el caso de la aplicación ejemplo, se utilizará arquitectura de software Model-View-Controller (MVC), por lo que el diseño se verá estructurado en tres componentes arquitectónicos. En caso de que no se utilice una arquitectura de software, el diseño será organizado en un único componente. Continuando con la construcción de la aplicación se procede a la creación y organización de las clases iniciales de cada uno de los componentes de la arquitectura MVC. Por ejemplo, el componente Model inicialmente tendrá las siguientes clases (Figura 5): Player: Contiene información referente al jugador (por ejemplo su nombre). Además, tiene conocimiento de las fichas que tiene para jugar y que no se encuentran sobre el tablero. Esto se puede ver en el juego del scrabbel, en el cual los jugadores disponen de letras (fichas) con las que deben formar palabras sobre el tablero. Piece: Existen muchos juegos de tablero en los que se utilizan diferentes piezas o fichas. Esta clase representa a tales piezas. Una pieza tiene el conocimiento de cuales son las celdas con las que se puede operar, a partir de una celda origen, con una determinada pieza. Esto se ve en el juego de ajedrez, en donde se sabe que la pieza alfil solo se puede mover a celdas diagonales contiguas. Board: Representa al tablero de juego y provee métodos para acceder a las distintas celdas, además completa el chequeo de si el movimiento de una pieza es válido. Siguiendo con el ejemplo de ajedrez, se puede verificar a nivel pieza que un alfil se mueva solo en diagonal, pero a este nivel se desconoce si en la celda destino se encuentra alguna otra pieza del mismo color, por ejemplo. Esta responsabilidad es del tablero. Cell: El tablero esta compuesto por celdas. La celda brinda mecanismos para poner y sacar piezas de ella. Game: Contiene la lógica y reglas del juego y tiene conocimiento del estado del mismo, los jugadores, maneja los turnos, fichas sobre el tablero, etc. Figura 5: Clases que diseñan (inicialmente) el componente arquitectónico Model 4.1.2. Creación de instancias de patrones de diseño Es posible que el usuario desee utilizar en su diseño varias veces un determinado patrón dado (por ejemplo, el patrón Singleton). Es por ello que surge el concepto de instancia de patrón de diseño. Una instancia puede verse como una “copia” de un patrón de diseño dado. Incluye además, información para mantener vínculos entre las clases del usuario y las clases que conforman la estructura del patrón. Estos vínculos representan los roles. Un rol indica que clase del modelo del usuario juega el rol de una clase que se encuentra dentro de la estructura de la instancia de un patrón. Entonces, cualquier modificación que ocurra sobre una clase de la instancia de un patrón, afectará directamente a una clase del usuario. Para incorporar un patrón de diseño (de los que se encuentran en el catálogo de pLinker) a la estructura de clases preexistente, primero se debe establecer el nombre de la instancia. Luego se debe determinar cual será el patrón a instanciar. Los patrones disponibles dependerán del componente arquitectónico seleccionado ya que solo se mostrarán aquellos que son factibles de utilizar. Sin embargo, el usuario puede no tener en cuenta el componente arquitectónico y utilizar cualquier patrón de diseño incluído en el catálogo. Una vez seleccionado el patrón de diseño a instanciar, la herramienta propone alternativas del mismo. Tales alternativas estarán dadas por las relaciones existentes entre patrones. Solo aparecerán como alternativas aquellas relaciones entre patrones cuyo tipo implique que deben usadas antes de la instanciación de un patrón. Continuando con el componente arquitectónico View, la Figura 6.a muestra las clases que diseñan inicialmente dicho componente. Cada una de estas clases es encargada de representar gráficamente los diferentes elementos de un juego de tablero. Se puede ver como la clase GameView tiene la responsabilidad de manejar la vista correspondiente al tablero (BoardView) y las vistas de los jugadores (PlayerView). Para reducir esta complejidad, y manejar esta jerarquía de vistas de manera homogénea, es posible utilizar el patrón de diseño Composite [GHJV95]. Al intentar instanciar un patrón para el diseño del componente View, pLinker ofrecerá el Composite puesto que dicho patrón es frecuentemente usado en este componente arquitectónico. Entre las actividades que surgirán cuando se cree una instancia de este patrón estarán las de renombrar las clases y los métodos (por ejemplo, AbstractComponent por AbstractView y operation por paint). En cuanto a los roles, la clases PieceView y PlayerView jugarán el rol de ConcreteComponents, ya que pueden verse como hojas del árbol de vistas. De manera similar, las clases BoardView, GameView y CellView jugarán el rol de AbstractComposite. En la Figura 6.b se la instanciación de el patrón Composite. 4.1.3. Activación de las relaciones entre patrones Una vez instanciado un patrón, pLinker propone al usuario, los patrones de diseño que pueden ser utilizados en conjunto con el primero. Solo aparecerán aquellas relaciones entre patrones cuyo tipo implique que deben usadas después de la instanciación de un patrón dado. 6.a 6.b Figura 6.a: Clases que diseñan el componente View 6.b: Uso del patrón Composite en el diseño del componente View Para el diseño del juego, se activará la relación entre los patrones de diseño Composite y Decorator (Figura 7). Esto permitirá que las diferentes vistas (que ahora forman parte del Composite) se dibujen de diferente manera, dependiendo posiblemente, del estado del objeto que representan. Por ejemplo, es posible que cuando el usuario seleccione una celda del tablero, la misma se dibuje con un recuadro. Figura 7: Activación de la relación entre los patrones Composite y Decorator Entonces, pLinker se encarga de actualizar el modelo de clases del usuario para reflejar la activación de dicha relación. La activación de una relación implica que se ha utilizado un nuevo patrón (o instancia del mismo) en el diseño del usuario. Entonces, la herramienta crea automáticamente una instancia de dicho patrón. De esta manera, a medida que se van aplicando patrones en el diseño, la herramienta va asistiendo al diseñador para la incorporación de nuevos patrones de manera de completar el diseño de la aplicación. Una vez que las posibles relaciones entre patrones han sido mostradas por la herramienta y utilizada esa información por el diseñador, este último deberá analizar el diseño resultante en caso de tener que incorporar nuevas clases o patrones no surgidos de las relaciones. 4. Conclusiones En este trabajo se realizó un estudio y clasificación de los tipos de relaciones existentes entre patrones de diseño. Se identificaron puntos en común que permitieron clasificar y documentar más formalmente tales tipos de relaciones. Como resultado de este estudio surgió un esquema de documentación similar al que es utilizado para describir patrones de diseño, lo que facilita la comprensión y la forma de aplicación de las relaciones entre patrones. Al descubrirse una relación entre dos patrones de diseño dados, no solo es posible clasificarla, sino que también se la puede documentar de manera que permita utilizarla posteriormente en una herramienta de desarrollo que contemple el uso patrones de diseño y relaciones entre los mismos. Con el objetivo de asistir al usuario en la construcción de diseños utilizando patrones y sus relaciones de manera simple, se implementó pLinker, una herramienta gráfica que permite modelar diagramas de clase UML e incorporar patrones en ellos y aprovechar las relaciones existentes entre los mismos. pLinker provee mecanismos que facilitan la incorporación de patrones a un diseño preexistente de manera simple, permitiendo establecer vínculos entre las clases del patrón y las clases del usuario para mantener la consistencia entre las instancias de patrones de diseño. Al insertar un patrón de diseño en un diagrama de clases dado, pLinker ofrece opciones que implícitamente llevan a “activar” relaciones entre el patrón original y aquellos con los cuales esté relacionado. Al activar una relación entre patrones, pLinker se encarga de mantener consistente el modelo del usuario, tomando para ello la información propia de la relación. Por otro lado, pLinker permite trabajar con arquitecturas de software y sus respectivos componentes arquitectónicos, dando la posibilidad de indicar cuales son los patrones de diseño frecuentemente usados en un determinado componente arquitectónico, mejorando así la posible elección y uso de un determinado patrón, dentro de un diseño dado. La configuración de pLinker está fuertemente relacionada con la documentación de relaciones entre patrones propuesta. Es por ello que es posible tomar dicha información e incorporarla sin mayores problemas a la herramienta. 5. Bibliografía [AISJ+77] [BASS97] [BMRS+96] [Garlan94] [GHJV95] [Grand98] [JHotDraw] [Larman98] [Lorenz97] [Meijers96] [Noble98] [Rumbaugh96] [Yeates97] [Zimm94] C. Alexander, S. Ishikawa, M. Silverstein, M. Jacobson, I. Fiksdahl-King, and S. Angel. A Pattern Language - Towns-Buildings-Construction. Oxford University Press, 1977. Len Bass, Paul Clements and Rick Kazman, Software Architecture in Practice. AddisonWesley, 1997. Frank Buschmann, Regine Meunier, Hans Rohmrt, Peter Sommerlad, and Michael Stal, Pattern-Oriented Software Architecture - A System of Patterns. Wiley and Sons Ltd, 1996. David Garland and Mary Shaw, An introduction to Software Architecture. CMU-CS-94166, School of Computer Science, Carnegie Mellon University, Pittsburgh, PA 15213-3890, 1994. Erich Gamma, Richard Helm, Raph Johnson, and John Vlissides, Design Patterns – Elements of Reusable Object-Oriented Software. Addison-Wesley, Reading, MA, 1995. Mark Grand, Patterns in Java: a catalog of reusable design patterns illustrated with UML. Wiley and Sons, Inc, 1998. Erich Gamma and Thomas Eggenschwiler, A Java GUI framework for technical and structured Graphics. http://www.jhotdraw.org. Claig Larman, Applying UML and patterns. Upper Saddle River, N.J. Prentice Hall PTR, 1998. D.H. Lorenz, Tiling Design Patterns – a case studio. ECCOP Proceeding, 1997. Marco Meijers, Tool Support for Object-Oriented Design Patterns, Master’s Thesis. Utrecht University, CS Dept, INF-SCR-96-28, August 1996. James Noble, Classifying Relationships Between Object-Oriented Design Patterns. Microsoft Research Institute, Macquarie University, Sydney, Australia, 1998. James Rumbaugh, Michael Blaha, William Premerlani, Frederick Eddy, William Lorensen, Modelado y Diseño Orientados a Objetos. Metodología OMT. Prentice Hall, 1996. S.A. Yeates, Design a garbage collector using design patterns. TOOLS Pacific 25, 1997. Walter Zimmer, Relationships between design patterns in Pattern Languages of Program Design, Addison-Wesley, 1994.