Compito d'esame: visite mediche

Testo

Requisiti

L'applicazione da progettare gestisce le visite mediche di un reparto ospedaliero: pazienti, medici, visite e reparti. Di tutte le persone, quindi sia pazienti che medici, interessano nome, cognome e anno di nascita. Dei medici interessa la specializzazione (una stringa). I pazienti possono prenotare una visita presso un reparto. In seguito, la visita può venire assegnata a un medico. Ogni visita ha un codice (una stringa). Ogni paziente può prenotare quante visite vuole, ma ogni visita viene prenotata da un solo paziente. La visita è sempre e soltanto in un reparto. A un medico possono venire assegnate al massimo ottanta visite, ma non c'è un minimo. Quando la visita viene prenotata non è assegnata a nessun medico, e nel seguito può venire assegnata a un singolo medico, ma non di più. Può succedere di dover disassegnare tutte le visite di un medico dato. Un medico afferisce a uno e un solo reparto, ma non è detto che effettui visite solo per quel reparto.

Uno degli aspetti dell'applicazione è l'evoluzione delle visite. Inizialmente, una visita è Prenotata. Un evento Assegna la porta nello stato Assegnata; inoltre, questo evento assegna alla visita un medico, che è specificato nell'evento stesso. In condizioni normali, la visita diventa poi Effettuata a seguito di un evento Effettua. In caso di problemi, la visita può venire Sospesa da un evento Sospendi. Questo cancella l'assegnamento del medico alla visita. Una visita sospesa torna nello stato Assegnata a seguito di un evento Riassegna, che porta anche il nuovo medico; questo medico può o meno essere lo stesso medico a cui era inizialmente stata assegnata la visita; se è diverso, al medico a cui inizialmente era stata assegnata la visita viene inviato un messaggio di Notifica che include la visita. Una visita assegnata o sospesa può diventare Annullata se riceve un evento Annulla.

L'attività principale riceve come parametri un insieme di pazienti. Per prima cosa, crea l'insieme delle visite che questi hanno prenotato ma che sono ancora solo prenotate e non assegnate oppure sono sospese. Se non ce ne sono, si attende un certo tempo e si ripete la ricerca. Se invece ci sono, partono attività parallele. Nella prima, viene inviato un messaggio a tutti i pazienti di queste visite per informarli che la loro visita è ancora in questo stato. Nella seconda, viene inviato un messaggio al reparto di tutte queste visite per sollecitare un nuovo assegnamento. Quando la seconda sottoattività termina, si stampa una stringa che lo notifica. Questo conclude l'attività principale.

Domande

Domanda 1.
Basandosi sui requisiti riportati sopra, effettuare la fase di analisi producendo lo schema concettuale in UML per l'applicazione, comprensivo del diagramma delle classi (inclusi vincoli non esprimibili in UML), diagramma stati e transizioni per la classe Visita, diagramma delle attività, specifica del diagramma stati e transizioni, riportando solo gli stati, le variabili di stato ausiliarie, e le transizioni dovute agli eventi Assegna e Riassegna; la segnatura delle attività complesse, delle attività atomiche e dei segnali di input/output; la specifica della attività atomica di calcolo delle visite non effettuate e non annullate. Motivare, qualora ce ne fosse bisogno, le scelte di progetto.
Domanda 2.
Effettuare la fase di progetto, illustrando i prodotti rilevanti di tale fase e motivando, qualora ce ne fosse bisogno, le scelte effettuate. In particolare definire SOLO le responsabilità sulle associazioni del diagramma delle classi. Nella tabella, inserire anche il motivo di ognuna delle responsabilità usando le lettere M, O, R rispettivamente per molteplicità, operazioni e requisiti.
Domanda 3.
Effettuare la fase di realizzazione, producendo un programma Java e motivando, qualora ce ne fosse bisogno, le scelte effettuate. Èobbligatorio realizzare in Java solo i seguenti aspetti dello schema concettuale:

Diagrammi

Classi

[classi.fig]

Comportamenti

[comportamento.fig]

Attività

[attivita.fig]

Tabelle

Responsabilità

assegnatomedico
MR
visita
MO
afferiscemedico
M
reparto
invisita
MO
reparto
prenotapaziente
O
visita
M

Le transizioni degli eventi Assegna e Riassegna cambiano il medico assegnato a una visita. Questo richiede la responsabilità della visita sulla sua associazione con il medico.

La prima sottoattività atomica trova un sottoinsieme delle visite di un insieme di pazienti. Deve quindi conoscere le visite prenotate dai pazienti, e qundi i pazienti devono avere responsabilità sulle visite che hanno prenotato.

La seconda attività lanciata in parallelo sollicita i reparti delle visite. Quindi la visite hanno responsabilità sulla loro associazione con i reparti di afferenza.

Specifica

Comportamenti

InizioSpecificaStatiVisita
    Stato: {Prenotata, Assegnata, Sospesa, Annullata, Effettuata};
    
    Variabili di stato ausiliarie:
        iniziale: Medico
    
    Stato iniziale:
        statoCorrente = Prenotata
        medico = --
FineSpecifica
InizioSpecificaTransizioni Visita
   Transizione: Prenotata → Assegnata
   Evento:
      Assegna(medico:Medico)

   Condizione:
      nessuna

   Azione:
      pre: nessuna
      post: this.medico = medico &&
            iniziale = medico

   Transizione: Sospesa → Assegnata
   Evento:
      Riassegna(medico:Medico)

   Condizione:
      nessuna

   Azione:
      pre: iniziale != null
      post: this.medico = medico &&
	    (medico == iniziale || nuovoevento = Notifica{mitt: this, dest:iniziale})
FineSpecifica

Condizione e pre sono entrambe condizioni booleane. Quando sono false:

pre
l'azione della transizione non si può eseguire; è un errore inviare l'evento se la precondizione è falsa; va corretto;
condizione
la transizione si potrebbe anche eseguire, ma la specifica dice di non farlo; è previsto che possa succedere, non è un errore; la transizione non ha luogo e basta.

In questo caso, l'evento di riassegnamento non va inviato a una visita che non ha mai ricevuto un evento di assegnamento, che rende la variabile ausiliare non vuota. La precondizione iniziale != null viene resa vera dal precedente evento di assegnamento.

Nonostante quello che sembra, anche la postcondizione è una condizione booleana: indica una condizione che sarà vera dopo che l'azione è stata eseguita. Non è un comando (“fai questo”) ma una affermazione (“alla fine della transizione, questo sarà vero”). Si può immaginare di usarlo in un programma che verifica i comportamenti inviando l'evento e verificando che la postcondizione sia falsa; se lo è, segnala l'errore.

L'unica variabile ausiliaria è il medico a cui era stata inizialmente assegnata la visita, essendo l'unico dato che:

Deve essere mantenuto perché serve per inviare il messaggio di notifica dopo una sospensione e un riassegnamento, e non è sempre memorizzato nelle classi dati visto che viene cancellato dall'evento di sospensione.

Attività

Segnature

Principale(Set<Paziente>):
Attesa(Set<Paziente>) : Set<Visita>
Informa(Set<Paziente>):
Sollecita(Set<Visita>):
Fine():

L'attività prende un insieme di pazienti e trova le loro visite che non sono ancora o non sono più assegnate. Quindi ha come parametro di ingresso un insieme di pazienti e di uscita un insieme di visite.

Per le attività Informa e Sollecita non è richiesta l'implementazione, ma la segnatura sì. I requisiti dicono quali sono i loro dati di input e output:

Specifiche

InizioSpecificaAttivitaAtomica NonAssegnate
NonAssegnate(pazienti: Set) : (visite: Set)

    pre: nessuna
    post: visite = {visita |
                     (visita.stato == Prenotata || visita.stato == Sospesa) and
		     ∃ paziente .
                         (paziente.visita == visita and paziente ∈ pazienti)}
FineSpecifica

Come per le transizioni, anche le precondizioni e postcondizioni della attività sono condizioni booleane. Questa sottoattività atomica non ha precondizioni, mentre la postcondizione è che il risultato visite sia l'insieme delle visite prenotate o sospese dei pazienti dell'insieme. Quindi ogni sua visita:

Implementazione

Dati

L'associazione prenota collega ogni visita con il paziente che l'ha prenotata. Una visita ha un solo paziente, ma un paziente può prenotare più visite. È una associazione con molteplicità arbitraria dal lato dei pazienti e singola dal lato delle visite. Per questo i metodi hanno nomi diversi: Visita.setPrenota() e Paziente.aggiungiPrenota(). Essendo anche una associazione a responsabilità doppia, questi metodi chiamano entrambi lo stesso metodo di aggiunta ManagerPrenota.aggiungiPrenota() del manager.

La stessa cosa vale per le cancellazioni.

Comportamento

Ogni evento ricevuto da Visita causa la creazione di un nuovo oggetto VisitaFired. L'oggetto è quindi diverso per ogni evento, non è sempre lo stesso. I dati che vanno mantenuti da una transizione all'altra non si possono quindi memorizzare né nella classe VisitaFired né nel suo metodo esegui. Vanno memorizzati nella classe Visita. Questo vale in generale per tutte le variabili ausiliarie, che sono per definizione i dati da mantenere fra una transizione e l'altra e che non sono sempre memorizzati nelle classi dati.

Attività

Classi non richieste

Vengono fornite solo per permettere la compilazione delle altre. È un errore scriverle nel compito da consegnare in quanto non richiesto dalle specifiche.

Classi stub

Classi fisse