ANÁLISIS Y DISEÑO DE UN CASO DE USO “Reasignar Citas”

A lo largo de este documento vamos a ver paso a paso cómo realizar el análisis y el diseño del caso de uso de Reasignar Citas de un médico que podéis encontrar en el listado de ejercicios.
Flujo de Eventos ============= Reasignar Citas - El médico da su número de colegiado e indica el día para el que quiere cancelar sus citas. Antes de cancelar una cita se intenta reasignar a otro médico, siempre que tenga una cita NO ASIGNADA a la misma hora. - Hay que generar un listado con todas las citas canceladas o reasignadas (nombre del paciente, teléfono, fecha y hora cita, y si se ha podido, el nombre del nuevo médico asignado)

Medico

Fig. 1 Caso de Uso - Reasignar Citas

Fig. 2 Modelo del Dominio

Análisis
El primer paso es realizar el Diagrama de Colaboración. Para su realización, hay que tener claro qué vamos a representar. En el diagrama de colaboración sólo se muestra una de las diferentes ramas de ejecución que haya en el flujo de eventos del caso de uso. En este caso, vamos a realizar el diagrama de colaboración del Caso de Uso Reasignar Citas suponiendo que hay citas libres para la reasignación1. Para poder hacer correctamente el diagrama de colaboración necesitamos saber qué clases tenemos y cómo se relacionan entre ellas. Esa información nos viene dada en el diagrama de clases. Partiendo del modelo de dominio superior, las clases que vamos a utilizar son las siguientes:

Fig. 3 Diagrama de Clases (versión I)
1

En el enunciado nos dicen que cada médico ya tiene sus citas creadas (atributo SuAgenda). De modo, que las citas existen independientemente de que estén libres u ocupadas (según si tienen un paciente asignado o no)

En este caso se ha optado por implementar las relaciones entre Paciente y Cita y entre Médico y Cita de manera doble. Esto es, el Paciente y el Médico tienen un parámetro que es una ListaCitas, y una Cita guarda la referencia tanto al Médico como al Paciente. Obviamente no es la mejor solución para este caso de uso, pero así veremos el trabajo “extra” que supone tomar una decisión errónea.
Comenzamos dibujando el actor encargado de realizar el Caso de Uso y una única clase frontera que representará a todas las interfaces gráficas involucradas en este Caso de Uso

IU_RC Medico Cabecera

Sobre la clase frontera, vamos indicando la interacción entre el usuario y la interfaz.

Después del paso 1 tenemos el número de colegiado del médico, pero con eso no podemos hacer nada. En orientación a objetos no vale con conocer el valor de un atributo de un objeto, tenemos que conocer cual es la instancia concreta que tiene ese valor. Para encontrar esa instancia, lo único que podemos hacer es ir preguntando uno a uno a todos los objetos de tipo MédicoCabecera para ver qué valor tienen en el atributo NumColegiado, y cuando lo encontremos, ya sabremos sobre qué instancia concreta queremos trabajar. Para trabajar con los objetos, siempre usaremos un gestor como intermediario, NUNCA tendremos operaciones que vayan desde la interfaz directamente a un objeto entidad. Así que tenemos que tener un gestor (le llamaremos Gestor de Médicos, ya que va a trabajar con la entidad llamada MedicoCabecera) que nos ofrezca una operación, que lo que haga sea ir buscando uno por uno en todos los objetos de tipo Médico y mirando a ver qué valor tiene su atributo NumColegiado y esa operación devolverá como resultado, la instancia de tipo médico que tiene ese número de colegiado. Los gestores que definamos podrán conocer (si nos interesa) todas las instancias que existan de una o varias clases.

Si tiene que buscar un valor entre los objetos de tipo médico, le tendremos que decir qué valor tiene que buscar

Iremos uno a uno por todos los objetos de tipo médico. Esta operación no tendrá parámetros, ya que cada objeto nos dará su propio número de colegiado

Una vez que ya sabemos cual es el objeto de tipo médico con el que tenemos que trabajar, necesitaremos obtener sus citas. Para ello haremos uso del atributo SuAgenda que tienen los médicos. Pero realmente sólo nos interesan las citas de un médico en un día concreto (en la fecha que se ha introducido en el paso 1) y que estén ocupadas (que el atributo Enfermo no sea NULL). Por lo tanto, y aprovechando que nosotros decidimos qué hace cada operación y cómo funciona, vamos a definir una operación ObtenerCitas, que dado un médico y una fecha, devuelva una lista con las citas de ese médico en esa fecha. Perfectamente podríamos haber decidido hacerlo de otra manera y obtener todas las citas del médico, y luego filtrar las de la fecha concreta que nos interesan, o cualquier otra forma. Lo que hay que tener en cuenta es que hay que ser consecuente con las decisiones tomadas si la operación ObtenerCitas devuelve las citas ocupadas de una fecha concreta, además de ir al objeto médico y obtener la ListaCitas del atributo SuAgenda, tendremos que ir accediendo a cada uno de los objetos de esa lista y consultar su fecha y su atributo Enfermo, para ver si tienen que formar parte del resultado o no.

Los pasos 6 y 7 tienen que salir del GestorMédicos, porque es ahí donde está la operación ObtenerCitas, y los pasos 6 y 7 son parte de esa operación

Ya tenemos la lista de todas las citas que hay que reasignar (las ocupadas de ese médico en ese día). Ahora tal y como nos dice el flujo de eventos del caso de uso, tenemos que intentar reasignarlas. Para ello el primer paso es buscar una cita el mismo día a la misma hora que esté libre (recordad que lo primero que hemos decidido es que sí que iba a haber citas libres para reasignar, pero aún así tendremos que hacer las operaciones para buscarlas). ¿Cómo sabemos si una cita está libre? Porque no tiene un paciente asignado en su atributo Enfermo. Por lo tanto, vamos a definir una función BuscarCitaLibre, que dada una cita (de las que hay que reasignar) obtenga otra cita libre el mismo día a la misma hora. Si no hubiera una cita libre el mismo día a la misma hora, esta operación devolvería NULL, pero estamos haciendo la rama de ejecución en la que sí hay citas libres, así que seguiremos el diagrama suponiendo que esta operación nos va a devolver una cita.

Esta operación se ejecuta sobre la cita pasada como parámetro, para saber qué fecha y hora tenemos que buscar en las citas libres Esta operación se ejecuta sobre cada cita existente para ver si es el mismo día y a la misma hora. Si lo es, ejecutaremos el paso 11 para ver si está libre

Una vez que ya hemos encontrado una cita libre el mismo día y a la misma hora, lo que hay que hacer es reasignar el paciente. Para ello vamos a definir una operación ReasignarCita, que dada la cita vieja y la nueva, reasigne al paciente de una a otra.

Para obtener la referencia al paciente de la cita vieja Para dejar en la cita nueva, la referencia a el paciente Trabajo Extra: Añadir la nueva cita a la lista de Citas del Paciente y quitar la vieja (antes de destruirla!) Quitamos la cita vieja de la lista de citas del Médico

Por último necesitamos obtener la información necesaria para mostrar por pantalla todo lo que piden: nombre del paciente, teléfono, fecha y hora de la cita y el nombre del nuevo médico. Para ello vamos a crear una operación ObtenerDatos, que dada una cita obtenga los datos que necesitamos de esa cita.

Hay que saber a qué objeto de tipo paciente señala el objeto CitaNueva

Cuando ya sabemos cual es el objeto Paciente, obtenemos su nombre y su teléfono Obtenemos el objeto Medico de la CitaNueva y luego su nombre

Y con esto hemos finalizado el diagrama de colaboración de la rama de ejecución en la que hay citas libres de otro médico para realizar la asignación del caso de uso Reasignar Citas

Diseño
Gracias al diagrama de colaboración hemos identificado qué operaciones nos hacen falta y dónde tienen que estar, así que nuestro diagrama de clases (modelo del diseño) quedaría como sigue.

Fig. 4 Diagrama de Clases (Versión II)

Ya tenemos una parte del diseño de un caso de uso, el diagrama de clases, ahora vamos a realizar la otra parte, el diagrama de secuencia. En el diagrama de secuencia vamos a representar exactamente cómo va a funcionar el caso de uso, qué operaciones se ejecutan, dónde se ejecuta cada operación, si se repite, etc. Hay que tener en cuenta que en el diagrama de secuencia se muestran todas las alternativas al flujo de eventos principal, por lo que hay que ir indicando si esa parte del diagrama se ejecuta siempre o sólo cuando se cumple una cierta condición.

Diagrama de Secuencia Orientado a Objetos
En este caso vamos a empezar por el diagrama de secuencia usando Orientación a Objetos. Dicho diagrama es muy parecido al de colaboración y por eso lo usaremos como base.

El primer paso del flujo de eventos, al igual que en el diagrama de colaboración, es que el usuario introduzca su numero de colegiado y la fecha para la que quiere cancelar su citas. Para ello representamos el actor, la interfaz donde va a introducir los datos e indicamos el paso. Ahora viene una de las diferencias entre el diagrama de secuencia y el de colaboración. En éste último sólo representamos una interfaz para todo el caso de uso; en el de secuencia representamos tantas interfaces como se necesiten dentro del caso de uso. Y aunque en este enunciado no nos especificaban cuántas interfaces había, parece lógico suponer que aquella donde el usuario introduce los datos y aquella en la que se le muestran los resultados sean interfaces diferentes. Así que basándonos en esa suposición, cuando el usuario introduce su número de colegiado y la fecha, se abre otra interfaz que es la que lanza las operaciones necesarias para obtener la información de las citas reasignadas, canceladas, etc. Y será desde esa interfaz desde la que continuemos con las operaciones que nos indica el diagrama de colaboración. A esta nueva interfaz, tendremos que pasarle como parámetros toda la información que necesite para trabajar. En este caso, el número de colegiado y la fecha que el usuario haya introducido en la interfaz anterior. Otra diferencia con el diagrama de colaboración la encontramos en el paso 4. En el diagrama de secuencia se indican las repeticiones (qué se repite y cuando se repite). De esta manera representamos que la operación Buscar Médico del Gestor de Médicos lo que hará es ir buscando uno a uno por todos los objetos de tipo MedicoCabecera y consultar el valor de su atributo NumColegiado hasta que encuentre uno que coincida con el valor que le han pasado como parámetro. Ese objeto será el que a partir de ahora llamaremos elMédico, ya que es el médico concreto con el que queremos trabajar.

La siguiente diferencia viene a partir de la instrucción 13. En el diagrama de secuencia se representan todas las ramas de ejecución posibles del flujo de eventos del caso de uso. Por eso en este caso indicamos que hay una serie de operaciones, las que tienen una “a” cuya ejecución depende del cumplimento de una condición (que se encuentre una cita libre el mismo día a la misma hora). Las instrucciones 13a, 14a, etc. Sólo se ejecutarán si la condición se cumple. Y si la condición no se cumple, no hay que hacer nada especial por lo que no tenemos instrucciones alternativas (que numeraríamos seguidas de una “b” en caso de que existieran). Y por último tenemos las instrucciones de la 20 a la 25 que hay que ejecutarlas independientemente de que se haya encontrado una cita libre o no. Es por eso que no llevan ninguna letra. Estas instrucciones lo que hacen es obtener la información necesaria para mostrar por pantalla. Como esa información es la misma tanto si la cita se ha reasignado como si no, esas instrucciones no dependen de la condición. El único cambio entre una posibilidad y la otra sería que si la cita no se ha reasignado, los datos a mostrar son los que contiene el objeto CitaVieja, mientras que si la cita ha sido reasignada, esos datos son los de CitaNueva. Por lo tanto lo que cambiará será el parámetro. Es por eso que he preferido representar que los datos se obtienen de un objeto Cita genérico, porque a veces será CitaNueva y otras veces CitaVieja. Como resultado de realizar el diagrama de secuencia orientado a objetos, puede ocurrir que sea necesario añadir al diagrama de clases nuevas clases u operaciones. Esto ocurre cuando las ramas de ejecución que no hemos contemplado en el diagrama de colaboración, pero que sí aparecen en el de secuencia, necesitan nuevas operaciones. En este caso no ocurre, por lo que el diagrama de clases definitivo es el mismo que obtuvimos a partir del diagrama de colaboración.

Fig. 5 Diagrama de Clases (Versión Definitiva)

Diagrama de Secuencia usando Sistema de Gestión de BD
Para realizar el diagrama de secuencia usando un Sistema de Gestión de Bases de Datos, lo primero que tenemos que tener claro es qué tablas de la Base de Datos tenemos y cual es el contenido y la forma de estas tablas. Esta información la obtenemos del modelo del dominio. En nuestro ejemplo esas tablas serían las siguientes:

En este caso concreto, en la tabla Cita podemos usar el campo NumColegiado para formar la clave primaria, ya que sabemos seguro que toda cita estará relacionada con un médico, y que un médico sólo tiene una cita en una Fecha y Hora concretas. Otra cosa a tener clara es que cuando estamos trabajando con Bases de Datos, el diagrama de colaboración no nos sirve más que como una pequeña guía que nos puede decir cuál es el algoritmo a seguir, pero nada más. Si estamos trabajando con una Base de Datos podemos hacer uso de todas las ventajas que nos ofrecen (trabajar con las claves y no con referencias, posibilidad de unir tablas en una única consulta SQL, etc.). Por eso el diagrama de secuencia usando SGBD no van a coincidir los pasos, ni las operaciones con el diagrama de colaboración. Cuando realizamos un diagrama de secuencia usando un SGBD, la forma de acceder a los datos es mediante consultas SQL. Dichas consultas siempre se ejecutarán sobre el elemento llamado GestorBD mediante su operación execSQL. La operación execSQL se comporta distinto según el tipo de consulta SQL. Si la consulta es un SELECT.. se crea un nuevo elemento en el diagrama de secuencia llamado ResultadoSQL donde estará contenido en forma de tabla el resultado de ejecutar la consulta SQL sobre la Base de Datos. Para recorrer ese resultado extrayendo los datos contenidos, usaremos la operación next que nos sitúa en la primera fila del resultado que todavía no hayamos consultado. Una vez situados en una fila, podemos acceder a los datos de esa fila mediante el nombre de las columnas. Una vez recorridos todos los datos del resultado, lo cerraremos mediante la instrucción close. De este modo liberaremos la memoria ocupada por el resultado.

En la operación 3 gracias a las posibilidades que nos ofrece SQL hemos obtenido casi todos los datos que necesitamos para mostrar por pantalla posteriormente. Sólo falta obtener el nombre del médico. Al igual que en el diagrama anterior hay una serie de operaciones que sólo se ejecutarán cuando se cumpla una condición: que haya una cita libre el mismo día a la misma hora. Y también tenemos una serie de operaciones (de la 20 a la 24) que se van a ejecutar tanto si hemos encontrado la cita libre o no, pero con una pequeña diferencia. Si hemos encontrado una cita libre, el número de colegiado que usamos en la consulta SQL del paso 20 será el número de colegiado que tenga esa cita libre y que lo habremos obtenido en el paso 16a. Si no hemos encontrado ninguna cita libre, el número de colegiado del paso 20 será el que ha introducido el usuario en el primer paso. Por lo tanto, si lo necesitamos en el paso 20 hay que hacerlo llegar hasta ahí de alguna manera. Esa manera es como un parámetro de la operación 12. Si la operación 12 encuentra una cita libre, ese número de colegiado no sirve para nada, pero si no se encuentra la cita libre lo necesitamos para poder sacar el nombre del médico.