Esercizio 8
Si vogliono mantenere le informazioni su un deposito di contenitori di
liquidi.
Ogni contenitore (C) è dotato di un codice univoco;
i contenitori possono essere di due tipi: lattine (L)
e bidoni (B) entrambe queste categorie sono dotate
di un campo nome per identificare il liquido contenuto
e di un campo qta per dichiarare la quantità contenuta.
E' richiesta la presenza di una interfaccia CMP che
contenga un metodo confronta() in grado di effettuare
un confronto di peso fra due contenitori omologhi (L
o B) considerando che i bidoni hanno sempre una quantità
di liquido stoccato maggiore delle lattine.
Realizzare poi una classe U (utils) contenente un
metodo C[] filtra(C[] T, C c)
che riceve in ingresso un vettore T di contenitori
ed un contenitore campione.
Il metodo filtra deve restituire il vettore T ripulito
di tutti i contenitori che contengono lo stesso liquido del contenitore
campione (C c) passato come parametro .
Sia le lattine che i bidoni hanno in comune il codice univoco id,
questo costituisce l'attributo protetto ( accessibile solo agli oggetti
discendenti ) della classe C (contenitore).
Le classi L (lattine) e B (bidoni) sono delle specializzazioni della
classe C e quindi la estendono. Una prima configurazione, prevede
la presenza dell'interfaccia CMP in cima alla gerarchia delle classi:
L'implementazione del metodo int confronta(C x) verifica
dapprima che il contenitore passato come parametro sia omologo a quello
attuale (this) se questo si verifica viene restituita
la differenza fra le due quantità di liquido contenuto.
Viene dunque restituito un numero dotato di segno: positivo se il
contenitore attuale ha una quantità maggiore di quello passato,
zero se i due contenitori hanno la stessa quantità di liquido, un
numero negativo se il contenitore in ingresso ha una quantità maggiore
di quello attuale.
Si nota una differenza fra i due metodi confronta() nelle
due classi concrete L e B.
Nella classe L, prima di eseguire il confronto, si
attende l'esito dell'istruzione if(x instanceof L ) se
il contenitore passato non è una lattina viene restituto -1. Infatti se
il contenitore passato non è una lattina deve essere necessariamente un
bidone e per definizione i bidoni hanno un valore qta
maggiore delle lattine, quindi il risultato deve essere comunque negativo.
Il ragionamento contrario avviene nel metodo confronta()
scritto per la classe B.
La classe U riceve in ingresso un vettore T
di oggetti contenitore ed un oggetto di classe C,
poi usa il metodo equals (per le stringhe) per controllare
quali dei contenitori contenuti nel vettore hanno lo stesso liquido contenuto
nel campione(C c) : bisogna accedere, dunque, all'attributo
privato 'nome' delle classi L e B
ma facendo questa operazione a livello della classe C
è necessario che il metodo String getn() sia dichiarato
abstract nella classe C altrimenti questa non ne
ha la visibilità.
In poche parole il metodo filtra() conta quante ricorrenze
ci sono nel vettore che hanno lo stesso liquido dell'oggetto campione tramite
il contatore j; imposta quelle ricorrenze a null
poi crea un secondo vettore C[] vet
di lunghezza T.length-j e gli carica tutti gli elemente
che non siano null rimasti in T.
La classe C dei contenitori è astratta per due ragioni:
1.viene derivata dall'interfaccia CMP ma non implementa
il metodo astratto confronta()
2.contiene il metodo astratto String getn() che deve
essere usato nella classe U .
class liquid {
public static void main(String[] args) {
C l1=new L(1,"birra",1);
C l2=new L(2,"the",2);
C b1=new B(3,"the",10);
C b2=new B(4,"the",15);
C T[]=new C[5];
T[0]=l1; T[1]=l2; T[2]=b1; T[3]=b2;
T[4]=new B(5,"birra",20);
System.out.println("prima del filtro");
for (int i=0;i < T.length;i++)System.out.println(T[i]); System.out.println("l1
> l2 ?:"+l1.confronta(l2));
System.out.println("b1 > b2 ?:"+b1.confronta(b2));
U u=new U();
T=u.filtra(T,l2);
System.out.println("dopo il filtro");
for (int i=0;i < T.length;i++)System.out.println(T[i]);
}//fine main
}//fine classe
interface CMP { public int confronta(C x); } //fine
interfaccia
abstract class C implements CMP{
protected int id;
abstract String getn();
C(int codice) {id=codice;}
int getid(){return id;}
public String toString(){
String s="id:"; s+=id;
return s;
}//fine toString
}//fine C
class L extends C {
private String nome;
private int qta;
L(int cod,String s,int q) {super(cod); qta=q;nome=s;}
String getn(){return nome;}
public String toString(){
String s;
s=super.toString()+" nome:"+nome+" qta:"+qta;
return s;
} //fine toString
public int confronta(C x){
if(x instanceof L ){return (this.qta-((L)x).qta);}
else return -1;
}//fine confronta
}//fine L
class B extends C {
private String nome;
private int qta;
B(int cod,String s,int q) {super(cod);qta=q;nome=s;}
String getn(){return nome;}
public String toString(){
String s;
s=super.toString()+" nome:"+nome+" qta:"+qta;
return s;
} //fine toString
public int confronta(C x){
if(x instanceof B ){return (this.qta-((B)x).qta);}
else return 1;
}//fine confronta
}//fine L
class U{
C[] filtra(C[] T, C c){
int j=0;
for(int i=0;i < T.length;i++){ if((T[i].getn()).equals(c.getn())){T[i]=null;j++;}
}//fine for
int lg=T.length-j;
j=0;
C[] vet=new C[lg];
for(int i=0;i < T.length;i++)
if(T[i]!=null){vet[j]=T[i];j++;}
return vet;
}//fine filtra
}//fine U
Una seconda versione del programma prevede che ad implementare CMP siano le due classi concrete L e B ma la classe C deve rimanere astratta per quanto visto al punto 2 .
Il programma rimane invariato; cambiano solo
le intestazioni delle classi:
abstract class C {…}
class L extends C implements CMP {…}
class B extends C implements CMP {…}
Si può osservare come la
realizzazione dell'interfaccia sia comunque, non indispensabile
.
La classe astratta C con le dichiarazioni:
abstract String
getn();
abstract int getq();
Risolve in ogni caso il problema
In questo modo sia i metodi toString() e confronta (C,x) contenuti nella classe C possono accedere alle informazioni riservate :nome e qta contenute negli oggetti discendenti.
class liquidi {
public static void main(String[] args) {
//...istruzioni
}//fine main
}//fine classe
abstract class C {
private int id;
abstract String getn();
abstract int getq();
C(int codice) {id=codice;}
public int confronta(C x){
if(x instanceof L ){return (this.getq()-((L)x).getq());}
else return -1;
}//fine confronta
public String toString(){
String s="id:"+id+" liquido:"+getn()+" qta:"+getq();
return s;
}//fine toString
}//fine C
class L extends C {
private String nome;
private int qta;
L(int cod,String s,int q) {super(cod);qta=q;nome=s;}
String getn(){return nome;}
int getq(){return qta;}
}//fine L
class B extends C {
private String nome;
private int qta;
B(int cod,String s,int q) { super(cod);qta=q;nome=s;}
String getn(){return nome;}
int getq(){return qta;}
}//fine L
class U{
//...istruzioni precedenti
}//fine utils