Paola Magillo, Univestita' di Genova, Corso di Programmazione II per SMID, a.a. 2009-2010.

Lezione 12:

CASO DI STUDIO: GESTIONE DI UN DATA BASE DI ABBONATI - PARTE I

Vediamo un esempio che verra' poi usato nell'esame.

Supponiamo di avere un data base di abbonati (a un'azienda di trasporti, a un cinema, a una palestra... non importa). Costruiremo programma realizza questo data base con le sue operazioni, e un'interfaccia utente grafica che ne permette l'uso.

L'interfaccia avra' due versioni per essere usata rispettivamente:

  1. dall'abbonato per controllo e modifica dei propri dati personali (tranne nome, cognome e data di nascita, che non possono cambiare);
  2. dal gestore per creazione e modifica (rinnovo) di abbonamenti, ricerca di abbonamenti che hanno certe caratteristiche (es. quelli in scadenza per inviare avviso ai titolari...).

Come funziona il data base

Il data base gestisce un insieme di dati relativi ad abbonati (= persone con relativi abbonamenti) memorizzati su disco, ciascun abbonato in un file, tutti i file sono nella stessa directory. Inizialmente tutto resta su disco e non viene caricato.
Appositi criteri di ricerca sono usati per richiedere di caricare dal data base tutti e soli gli abbonati che hanno certe caratteristiche.
Quando l'utente effettua una ricerca, tutti gli abbonati che soddisfano il criterio di ricerca vengono caricati e memorizzati, possono essere mostrati all'utente, eventualmente modificati e poi riscritti sul file.

Tutto questo e' realizzato mediante un insieme di classi Java:

Classi per i dati da memorizzare

Persona memorizza le informazioni su una persona: cognome, nome, data di nascita, indirizzo, telefono, email.
Ha le funzioni per leggere e assegnare questi valori. Ha anche funzione che dato l'anno corrente ritorna l'eta' della persona.

Abbonamento memorizza la categoria di abbonamento (ordinario, per giovani, per anziani), la durata in mesi, il mese e l'anno di rilascio. Ha funzioni per leggere e assegnare questi valori, e funzioni che calcolano mese ed anno di scadenza.

La categoria di abbonamento e' rappresentata da un codice numerico. La classe definisce costanti per rappresentare i tre possibili valori, queste sono numeri interi che in rappresentazione binaria hanno un solo 1, in posizioni diverse tra loro. Questa caratteristica sara' sfruttata nella sotto-classe Criterio (= criterio di ricerca) per memorizzare piu' categorie in una variabile sola (vedi sezione per il data base).

InfoBase super-classe di Abbonato (vedi sotto) e di Criterio (vedi sezione per il data base), memorizza una persona (titolare di abbonamento) e un abbonamento (titolo posseduto dalla persona).

Abbonato sotto-classe di InfoBase, memorizza in piu' la password che serve all'utente per accreditarsi presso il database. Ha funzione per leggere e assegnare la password.

Classi per la gestione del data base

Criterio sotto-classe di InfoBase (vedi sezione per i dati), rappresenta un criterio di ricerca. Non memorizza niente in piu', ma le informazioni memorizzate sono intese come dei requisiti che un abbonato deve soddisfare per poter essere tra i risultati della ricerca. Possono assumere valori nulli (stringhe "" e interi 0), in questo caso si intende assenza di requisiti su quell'attributo.
Ha funzioni che servono a decidere se un Abbonato corrisponde ai requisiti.

La categoria puo' assumere valori multipli sfruttando il fatto che le costanti che rappresentano le categorie (vedi classe InfoBase) sono numeri interi che in rappresentazione binaria hanno un solo 1 in posizioni diverse tra loro. I valori muklipli si ottengono facendo OR bit a bit sulla rappresentazione binaria, es. mezzo = STUDENTI | ANZIANI (ottengo un numero che ha due 1: dove uno o l'altro aveva 1). Per vedere se due valori multipli hanno intersezione non vuota, facciamo AND bit a bit, es. categ1 & categ2, e guardiamo se e' non zero (ottengo un numero che ha 1 dove entrambi avevano 1).

LeggiScriviAbbonati contiene funzioni di classe per leggere da e scrivere su file un abbonato, secondo sintassi propria.
Usa al suo interno la classe MyReader vista in lezione 10, e la classe java PrintStream.

La sintassi e':

ABBONATO
Cognome: _stringa_
Nome: _stringa_
Anno: _intero_
Indirizzo: _sequenza_di_stringhe_
Telefono: _stringa_
Email: _stringa_
Categoria: _stringa_
Durata: _intero_
Rilascio: _due_interi_
Password: _stringa_
dove:
-- la stringa che esprime la categoria deve essere una fra: "ordinario", "studenti", "anziani";
--- i due interi che esprimono la data di rilascio corrispondono nell'ordine a mese (da 1 a 12) e anno;
-- memorizzare la password in chiaro sul file e' stupido! ma facciamo cosi' per non complicarci la vita (dovrebbe essere crittata).

Per convenzione il nome del file contenente un abbonato e' dato dalla concatenazione delle stringhe: cognome + nome + anno di nascita, ed estensione ".abb", sotto l'assunzione (ragionevole) che non ci siano due persone che hanno uguali tutti questi dati, e che una persona sia titolare di un solo abbonamento.

DataBase gestisce il data base degli abbonati. Su disco il data base e' una directory che contiene i file con le informazioni sugli abbonati (contrassegnati dall'estensione ".abb").
La classe per il data base contiene una costante per l'estensione sopra detta, la directory in cui si trovano i file degli abbonati. Inizialmente non carica nulla.
Ha funzioni che riportano informazioni di sommario come: numero di abbonati (= numero di file presenti nella directory).
Ha funzioni per cercare, caricare e ritornare (ma non vengono memorizzati qui) tutti gli abbonati che soddisfano un certo criterio di ricerca, e funzione per scrivere su file un abbonato (nuovo o modificato).
Il costruttore necessita del nome della directory.
Ha anche funzioni per costruire il nome file a partire dai dati personali di un abbonato.

Classi per gli utenti

Utente super-classe di UtenteAbbonato e UtenteGestore, memorizza il database usato dall'utente, un abbonato corrente e un booleano che indica se e' stato modificato.
Ha funzioni per:

Il costruttore accetta il nome di una directory e lo usa per costruire il data base.

UtenteAbbonato sotto-classe di Utente. L'attributo abbonato corrente, ereditato dalla super-classe, e' usato per memorizzare se stesso some abbonato.
Ha funzioni per: chiedere l'accesso al data base (esegue login con propri dati e password e carica i dati relativi all'abbonato se stesso); controllare se ha ottenuto accesso.

UtenteGestore sotto-classe di Utente, memorizza in piu': il criterio di ricerca corrente; un array di oggetti abbonato, che viene riempito ogni volta coi risultati dell'ultima ricerca.
L'attributo abbonato corrente, ereditato dalla super-classe, e' usato per memorizzare l'abbonato selezionato (scelto tra quelli caricati nell'array, o uno nuovo).
Ha funzioni per:

Note generali

Tutte le classi che costituiscono questo esempio sono predisposte per essere documentate con Javadoc (vedere lezione 11).
Scaricare tutti i file java nella directory corrente e poi digitare "javadoc *.java". Questo genera documentazione per tutte le classi, il file da cui partire (con l'indice) e' poi quello di nome "index.html".

Qui abbiamo dato solo un inquadramento generale delle classi, che spiega: a che cosa servono, che collegamenti hanno fra loro. Per tutti gli altri dettagli si rimanda alla documentazione javadoc.

Scriviamo main di esempio

Saranno due: uno per l'utente abbonato e uno per l'utente gestore.

Utente abbonato -- aggiungiamo alla classe UtenteAbbonato un main che fa le seguenti cose:

  1. Guarda quanti parametri ci sono sulla command line (basta guardare args.length)
  2. Se non e' esattamente uno, esce mostrando messaggio di errore.
  3. Se e' uno, lo usa come nome della directory contenente il data base, carica le informazioni del data base (basta costruire un UtenteAbbonato passando il nome dir come parametro).
  4. Chiede da standard input cognome, nome, anno di nascita e password da usare per accedere al database, e li memorizza in apposite variabili.
  5. Chiede accesso al data base (la funzione apposita carica anche i dati dell'abbonato se stesso).
  6. Stampa su standard output tale abbonato.
  7. Chiede da standard input nuovo email e lo memorizza.
  8. Cambia email dell'abbonato.
  9. Salva nel data base l'abbonato cosi' modificato.

Utente gestore -- aggiungiamo alla classe UtenteGestore un main che fa le seguenti cose:

  1. Guarda quanti parametri ci sono sulla command line (basta guardare args.length)
  2. Se non e' esattamente uno, esce mostrando messaggio di errore.
  3. Se e' uno, lo usa come nome della directory contenente il data base, carica le informazioni del data base (basta costruire un UtenteGestore passando il nome dir come parametro).
  4. Crea un nuovo abbonato e lo salva.
  5. Crea un criterio di ricerca e ne imposta alcuni campi (a piacere, potete poi provare a variare)
  6. Effettua una ricerca nel data base con quel criterio.
  7. Stampa su standard output tutti gli abbonati trovati.