edutecnica

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