Esempio di esercizio al calcolatore dell'anno scorso.
Gli esercizi d'esame saranno anche su cose fatte nelle prossime settimane.
Si vuole realizzare un programma per la gestione delle camere di un albergo. Per ogni camera, si deve memorizzare il suo numero, il fatto che la camera sia occupata o meno, e in tal caso, il nome della persona che la occupa. Dal momento che le camere hanno prezzi diversi, va anche memorizzato il prezzo, nel caso in cui la camera è occupata.
Il testo è diviso in due parti.
Scrivere una classe Camera in modo che ogni istanza rappresenti un singolo oggetto, e che abbia i seguenti metodi:
numero della prima stanza occupazione persona occupante prezzo numero della seconda stanza ...
Se la stanza è occupata, il nome dell'occupante non è significativo; ogni stanza occupa comunque quattro righe nel file; se il canale di input termina, il metodo deve restituire null; il dato occupazione è la stringa "occupata" oppure "libera"
Nota: il nome della persona è memorizzato come una unica stringa.
Scrivere una classe Albergo che gestisce l'insieme di tutte le stanze dell'albergo. I dati si trovano memorizzati in un file. La classe deve implementare i seguenti metodi:
Si fa una parte per volta.
Per ogni parte, si va per ordine.
Non c'è scritto, ma si assume che le classi devono essere incapsulate.
Il programma di prova e un file di esempio vengono dati:
import java.io.*; class ProvaCamera { public static void main(String arg[]) throws Exception { FileReader r=new FileReader("lista.txt"); BufferedReader b=new BufferedReader(r); Camera c, d; c=Camera.read(b); d=Camera.read(b); c.stampa(); d.stampa(); // stampa il nome dell'occupante della prima System.out.println(c.getNome()); // occupa la seconda stanza d.occupa("Francesco Totti", 80); // stampa di nuovo la seconda stanza d.stampa(); } }
Viene anche dato il file lista.txt
I dati del problema:
Testo | Cosa va fatto |
---|---|
Per ogni camera, si deve memorizzare ... | classe Camera |
il suo numero, il fatto che la camera sia occupata o meno, e in tal caso, il nome della persona che la occupa | componenti: numero, booleano, stringa |
Dal momento che le camere hanno prezzi diversi, va anche memorizzato il prezzo, nel caso in cui la camera è occupata. | componente intera (prezzo) |
Il fatto che le componenti nome e prezzo non siano significative quando la stanza è libera è irrilevante.
In ogni caso, queste componenti mi servono.
Se la camera non è occupata, non le uso.
Componenti:
class Camera { private int numero; private boolean occupata; private String nome; private int prezzo; // metodi }
Voglio una classe incapsulata, quindi tutte le componenti devono essere private.
Dopo aver fatto questo, provare a compilare.
Non è bene fare tutto e poi compilare: se ci sono errori, non si capisce dove sono.
Inizializza l'oggetto con i parametri passati.
class Camera { private int numero; private boolean occupata; private String nome; private int prezzo; Camera(int n, String nome, boolean o, int p) { this.numero=n; this.occupata=o; this.nome=nome; this.prezzo=p; } // altri metodi }
Solito costruttore con parametri.
Compilare anche a questo punto.
Per provare, fare una di queste due cose:
Sulla base dei nomi dei metodi, e dei loro argomenti, riesco a scrivere tutte le intestazioni.
Se i metodi tornano un valore, tornare una costante:
import java.io.*; class Camera { private int numero; private boolean occupata; private String nome; private int prezzo; Camera(int n, String nome, boolean o, int p) { this.numero=n; this.occupata=o; this.nome=nome; this.prezzo=p; } int getNumero() { return 0; } boolean getOccupata() { return false; } String getNome() { return ""; } int getPrezzo() { return 0; } void occupa(String nome, int prezzo) { } void stampa() { } static Camera read(BufferedReader b) throws IOException { return new Camera(0, "", false, 12); } }
Questo permette di provare subito la classe.
Poi metteremo le istruzioni un metodo per volta.
I metodi get... restituiscono il valore di una componente:
class Camera { private int numero; private boolean occupata; private String nome; private int prezzo; // costruttore int getNumero() { return this.numero; } boolean getOccupata() { return this.occupata; } int getPrezzo() { return this.prezzo; } // altri metodi }
Unico caso particolare: il metodo getNome:
String getNome() { if(this.occupata) return this.nome; else return ""; }
Compilare
Si può anche provare con il programma: commentare le invocazioni di metodi che non sono stati ancora definiti nella classe.
Occupa mette dei valori in due componenti dell'oggetto.
void occupa(String nome, int prezzo) { this.occupata=true; this.nome=nome; this.prezzo=prezzo; }
Metodo di stampa:
void stampa() { System.out.print("["+this.numero+", "+this.nome+", "); System.out.println(this.occupata+", "+this.prezzo+"]"); }
Ho un oggetto BufferedReader.
Per leggere una linea, basta invocare readLine su questo oggetto.
Devo mettere import java.io.*; e throws IOException
È un metodo statico: l'oggetto Camera viene creato.
import java.io.*; class Camera { // componenti e altri metodi static Camera read(BufferedReader b) throws IOException { int n, p; String nome; boolean o; String s; s=b.readLine(); if(s==null) return null; n=Integer.parseInt(s); s=b.readLine(); if(s==null) return null; if(s.equals("occupata")) o=true; else o=false; s=b.readLine(); if(s==null) return null; nome=s; s=b.readLine(); if(s==null) return null; p=Integer.parseInt(s); return new Camera(n, nome, o, p); } }
Nota: nel file, c'è prima l'occupazione e poi il nome.
Invece il costruttore ha questi due parametri nell'ordine opposto.
E con questo, la prima parte è fatta!
Per provarla, compilare anche ProvaCamera.java, che già si trova sul disco.
Anche il file di prova lista.txt si trova già sul disco.
Non iniziare la seconda parte se la prima non è stata terminata!
Il programma di prova si chiama ProvaAlbergo.java
L'albergo ha come unica componente il nome del file in cui si trovano i dati:
import java.io.*; class Albergo { private String nomefile; // costruttore e metodi }
Questo vale per tutti gli esercizi d'esame: si assume che ogni oggetto sia la rappresentazione di un file.
È il costruttore standard:
import java.io.*; class Albergo { private String nomefile; Albergo(String s) { this.nomefile=s; } // metodi }
Spesso, la definizione del costruttore suggerisce le componenti.
Se il costruttore ha come argomento una stringa che è un nome di file, allora la stringa potrebbe essere una componente dell'oggetto.
I due metodi fanno una operazione su tutti gli oggetti del file.
Lettura di un oggetto da file: Camera.read(b), dove b è un BufferedReader
Devo quindi:
Come al solito:
import java.io.*; class Albergo { void stampaOccupate(int p) throws IOException { FileReader r=new FileReader(this.nomefile); BufferedReader b=new BufferedReader(r); ... } }
Il ciclo standard è:
while(true) { leggi elemento; se e' null break; fai qualcosa con l'elemento }
Qui si legge un oggetto Camera invece dell'oggetto String
Stampiamo tutti gli elementi:
void stampaTutte() throws IOException { FileReader r=new FileReader(this.nomefile); BufferedReader b=new BufferedReader(r); Camera c; while(true) { c=Camera.read(b); if(c==null) break; c.stampa(); } }
Devo stampare solo le camere occupate che abbiano prezzo minore di p
Il ciclo è lo stesso; cambia solo l'operazione che faccio sull'oggetto.
void stampaOccupate(int p) throws IOException { FileReader r=new FileReader(nomefile); BufferedReader b=new BufferedReader(r); Camera c; while(true) { c=Camera.read(b); if(c==null) break; if(c.getOccupata() && (c.getPrezzo()<p) ) c.stampa(); } }
No, perchè il primo sicuramente contiene errori sintattici.
Compilare la classe solo con il primo.
Eseguire il programma di prova:
int totalePrezzo() throws IOException { return 0; }
Stessa struttura.
Si tratta di un totale
Uso il metodo dell'accumulatore (risultato parziale)
Il ciclo è sempre quello; cambia solo l'operazione da fare sugli oggetti.
int totalePrezzo() throws IOException { FileReader r=new FileReader(nomefile); BufferedReader b=new BufferedReader(r); Camera c; int somma=0; while(true) { c=Camera.read(b); if(c==null) break; if(c.getOccupata()) somma=somma+c.getPrezzo(); } return somma; }
A parte int somma=0 e if(...), è lo stesso ciclo di prima.