4.- Diseño del sistema.

    Comenzaremos la parte del diseño citando a G. Booch :

        "El propósito del diseño es de crear una arquitectura para la naciente implementación, [...] el diseño arquitectural sólo puede comenzar una vez que el equipo tenga un entendimiento razonable de los requerimientos del sistema. [...] El diseño, como el análisis, nunca termina realmente hasta que el sistema final es entregado. Durante esta fase, se alcanza un cierto grado de culminación al poner en su lugar la mayoría de las decisiones estratégicas de diseño y al establecer políticas para diversos problemas tácticos. [...] El diseño se enfoca en la estructura, estática y dinámica, su propósito principal es de crear el 'esqueleto' concreto del sistema sobre del cual todo el resto de la implementación se basa."

    Estas palabras definen claramente qué es el diseño, la creación de la estructura básica del sistema es la tarea clave, aunque también se buscan otras cosas, en particular patrones que simplifiquen el diseño y posibilidades de reuso entre otras.

    Durante la etapa de diseño vamos a refinar las partes fundamentales para la aplicación. Para lograrlo, es conveniente comenzar a buscar patrones de diseño, a continuación describimos esto de manera más detallada.

4.1 Patrones de diseño.

    De acuerdo con el libro 'Design Patterns' , un patrón es una "solución simple y elegante a problemas específicos dentro del diseño de aplicaciónes orientadas a objetos, los patrones capturan soluciones que han sido desarrolladas y han evolucionado a lo largo del tiempo, de ahí que normalmente no son el tipo de soluciones que se tienden a generar de manera inicial, reflejan el trabajo de los desarrolladores que han luchado por obtener una mayor posibilidad de reuso y flexibilidad en su software. Los patrones de diseño capturan estas soluciones de una manera fácil de aplicar."

    Una vez que se ha terminado con el análisis, conviene detenerse a estudiar el resultado principal de esa etapa, es decir el diagrama de clases de análisis. Es importante buscar que partes pueden ser mejoradas mediante el uso de algún patrón de diseño. Para ello es útil consultar algun catálogo de patrones y mediante sus descripciones tratar de encontrar alguno que se ajuste o que provea alguna solución al problema que se tiene.

    En nuestro caso particular, buscamos en el libro 'Design Patterns' y al leer las descripciones nos encontramos con la siguiente:

Estrategia (315) Define una familia de algoritmos, encapsula cada uno, y los hace intercambiables. La estrategia permite que los algoritmos varien independientemente de los clientes que los utilizan.

    Al mirar de manera más detallada su descripción, vemos que se recomienda aplicar este patrón entre otras cosas cuando:
 

    Si recordamos los requerimientos de la aplicación, nos viene a la mente el hecho de que es importante poder aplicar algoritmos diversos, y se deben poder agregar más posteriormente. Este patrón parece ofrecer una solución adecuada al problema que se nos presenta. Continuemos estudiandolo con más detalle.

    El diagrama de clases del patrón es el siguiente:

    Los participantes son:

    La colaboraciones son:
      Funcionamiento:

    Este patrón funciona de la manera siguiente: Al crear la instancia del contexto, este instancia a su vez alguna de las EstrategiasConcretas. Ahora cuando se llama a InterfaseDeContexto, esta a su vez llamara a InterfaseDeAlgoritmo y automáticamente se seleccionará la interfase deseada, sin necesidad de recurrir a sentencias condicionales (switch-case) para la seleccion del algoritmo correcto.

    Usos:

    Este patrón se adapta bien al problema de aplicar múltiples algoritmos. También puede ser utilizado para la creación de ventanas.

    Problemas:

    La desventaja que presenta este patrón para el problema que se nos presenta es que este patrón se limita a la selección de una sola de las estrategias que queda intimamente asociada al objeto Contexto. En nuestro caso en particular, no deseamos que sólo se pueda crear un algóritmo que se quede instanciado durante toda la aplicación. Sin embargo, la idea de presentar una interfaz común a todos los clientes es muy interesante, así que proponemos una ligera modificación al patrón, cuyo diagrama de clases se muestra a continuación:


    Como podemos apreciar, ahora la relación que existe entre el Contexto y la Estrategia ya no es una agregación, sino una relación de uso. Esto sucede por que en la operacion InterfaseDelContexto se crea la instancia de la Estrategia, y esta se destruye al terminar la operación, de ahí que sea una relación de uso. El Cliente tiene una referencia del Contexto y así puede acceder a su InterfaseDelContexto. Cuando un cliente hace uso de esta interfase, pasa una referencia de sí mismo de tal forma que el Contexto a su vez se la transmita a la Estrategia al instanciarla. El resultado es que cualquier EstrategiaConcreta conoce a su cliente y puede acceder a sus operaciones.

    A diferencia del patrón Estrategia convencional, este es más flexible, pues el Contexto se instancia una sola vez (probablemente por la aplicación), y este se encarga de crear y destruir las instancias de EstrategiaConcreta que cree, pero se pueden solicitar las diversas estrategias cuantas veces sea necesario, y el cliente puede ser cualquiera que tenga una referencia al contexto.

 
4.3 Aplicación de los patrones.

    Una vez que hemos encontrado soluciones aplicables al problema que estamos tratando de resolver las tenemos que incorporar al modelo resultante del análisis. Si estudiamos el diágrama de clases propuesto en la parte de análisis, notamos que existen tres 'partes' principales en el problema; estas son:
 

    Primeramente estudiaremos cómo se aplica el patrón descrito anteriormente en la vista gráfica y en el procesador de imágenes, afortunadamente fue posible aplicar el mismo patrón para resolver dos problemas aparentemente distintos como se describe a continuación.
 

4.3.1 El manejador de ventanas.

    Uno de los puntos que recalcamos desde el inicio del análisis fue el de tener una abstracción para la vista que llamamos VistaGrafica. La ventaja de hacer una abstracción de la parte interactiva es que podemos separarla de las demás clases, y sobre todo, podemos aislar el código que depende de la plataforma, puesto que normalmente las interfases de usuarios son una de las partes más dependientes de la plataforma que hay en la aplicación.

    Basándonos en el patrón estrategia, que 'define una familia de algoritmos, encapsula cada uno y los hace intercambiables de tal forma que los algoritmos varien de manera independiente de los clientes que los usan', realizamos una interfase común a todas las ventanas, esta interfase la provee la clase 'ManejadorDeVentanas'. A continuación se muestra el diagrama de las clases que involucran esta solución.


 
    Podemos ver que se tiene la misma situación que se describió anteriormente en el patrón Estrategia modificado.

    La aplicación crea la instancia del manejador, que será único en la aplicación. Cualquier clase que necesite algun tipo de interacción por parte del usuario tiene que conocer al manejador de ventanas, la aplicación se puede encargar de proveer una referencia a este. Se muestra aqui que la C_ColeccionDeDatos tiene una referencia al manejador, así, cualquier clase instanciada a partir de esta podrá pedir interaccion.

    La interfase común del manejador es la función SeleccionaVentana(), a través de esta función cualquier objeto puede pedir que se cree una ventana. Aunque no se muestra aquí, la ventana tiene una referencia de la clase cliente, de tál forma que pueda comunicarse con él.

    Una vez que se llama a SeleccionaVentana(), el manejador sigue siempre una serie de pasos idénticos:

1.- Instanciar la ventana, dandole a conocer a su cliente.
2.- Abrir ventana
3.- Activarla (entrar al ciclo de espera de eventos y recibir interacción por parte del usuario).
4.- Cerrar la ventana.
5.- Destruir la instancia.

    Al activarse la ventana, esta espera interacción por parte del usuario, y dado que tiene una referencia a un cliente, puede modificar atributos de la clase cliente. Una ventaja de esta solución es que un cliente puede pedir varias ventanas diferentes, otra es que el código específico de las ventanas se queda dentro de la implementación de la ventana y el cliente no tiene ningún conocimiento de cómo se realiza esto.
 

4.3.2 El procesador de imágenes.

    Otra parte en donde el patrón expuesto anteriormente facilitó una solución elegante fue en la aplicación de algoritmos. De la misma manera que para las ventanas, es necesario poder crear diversas instancias de los algoritmos y aplicarlas a clientes distintos.

    El diagrama de clases que muestra como quedó esta solución es el siguiente:

    En este diágrama la relación entre dos procesos que tienen como cliente al Stack de imágenes, pero debemos recordar que el cliente no forzosamente es de un tipo único.
 
    De igual forma que el ManejadorDeVentanas sigue unos pasos establecidos al instanciar una ventana, el ProcesadorDeImagenes también sigue una serie de pasos cuando se le solicita algún proceso a través de SeleccionaProceso(), estos son:

1.- Instanciar el proceso.
2.- Darle a conocer su cliente.
3.- Darle a conocer el manejador de ventanas.
4.- Inicializar el proceso.
5.- Ejecutarlo.
6.- Destruir la instancia del proceso.

    Es interesante notar que los procesos normalmente requieren interacción por parte del usuario, es por ello que se necesita 'darles a conocer' al manejador de ventanas, para que puedan solicitar una ventana.
 
    En lo que se refiere a patrones, esto es todo lo que se empleo durante el diseño. Esto no significa que no se puedan encontrar más patrones utiles para la aplicación, y de hecho, se debe tratar de emplear la mayor cantidad posible de ellos, pues como ya mencionamos anteriormente, son soluciones ya probadas y de ahí que sea ventajosa su utilización.
 
 


  Regresar al indice.             Ir a página siguiente.