PDA

View Full Version : [JAVA] Esempio di classe Abstract...ma così non è una porcata?!?!


D4rkAng3l
16-05-2009, 17:21
Ciao,
stavo vedendo un esempio di classe Abstract sul mio libro...ma sinceramente mi pare un po' una porcata come viene usata in questo caso...mi dite se oggettivamente sono cose da evitare o se invece non ho capito bene io?

Praticamente ho una classe astratta IntSet che mi fornisce una rappresentazione parziale di un insieme di interi e l'unica variabile di istanza è la variabile protected dimensione che indica la dimensione di tale insieme di interi.

Poi estendo tale classe abstract mediante la sottoclasse SortedIntSet che rappresenta un insieme di interi ordinati e che usa come variabile di istanza una OrderedIntList (una classe che mi rappresenta liste di interi ordinate).
In tale sottoclasse viene fornita la rappresentazione vera e propria del tipo di dati (che nella classe astratta non veniva fornita perchè poi magari potrei avere altre estensioni di IntSet che la implementano in altro modo...tipo ad esempio un'altra sottoclasse ConstantIntSet che rappresenta insiemi di interi di dimensione costante).

La variabile di istanza dimensione della superclasse è stata definita protected così quando ad esempio aggiungo con il metodo insert() o rimuovo con delete() un elemnto ad OrderedIntList posso accedere alla variabile protected dimensione ed aggiornarla.
Ma francamente mi pare un po' una porcata dichiarare tale variabile protected per 2 motivi:

1) Se cambio l'implementazione della superclasse devo cambiare l'implementazione delle varie sottoclassi.
2) Motivi di sicurezza perchè è visibile in tutto il package e qualsiasi metodo definito nel package potrebbe andare a modificarla.

Che mi dite in proposito? C'ho ragione io o mi sfugge qualcosa?

Il codice d'esempio del libro (parzialmente implementato) è il seguente:


public abstract class IntSet{

protected int dimensione; // La dimensione

// COSTRUTTORE
public IntSet(){
dimensione = 0;
}

// METODI ABSTRACT
public abstract void insert(int x); // Inserisce l'elemento x nell'insieme di interi
public abstract void remove(int x); // Rimuove l'elemento x dall'insieme di interi
public abstract Iterator elements(); // Per enumerare gli elementi dell'insieme di interi


// METODI IMPLEMENTATI
public boolean isIn(int x){
Iterator g = elements();
Integer z = new Integer(x);

while(g.hasNext())
if(g.next().equals(z)) return true;
return false;
}

public int size(){
return dimensione;
}

// IMPLEMENTAZIONE DEI METODI subset() e toString()
}



public class SortedIntSet extends Inset{

private OrderedIntList els;

public SortedIntSet(){ // COSTRUTTORE
els = new OrderedIntList();
}

public int max() throws EmptyException{
if(dimensione == 0) throw new EmptyException("SortedIntSet.max");
return els.greates();
}

public Iterator elements(){
return els.elements();
}

public boolean subset((SortdIntSet) s){
try{
return subset((SortedIntSet) s);
}catch(ClassCastException e){return super.subset(s);}
}

public boolean subset(SortedIntSet s){
.....
.....
.....
}

// Implementazione di insert e remove va quì
}




Poi ho qualche domanda teorica:

1) Estendendo IntSet la variabile protected dimensione viene ereditata in SortedIntSet...se si...perchè allora devo dichiararla protected per potervi accedere dalla classe figlia? Se era dichiarata private e viene ereditata perchè non ci si accede automaticamente?

2) Il costruttore della classe abstract IntSet non viene mai invocato dagli utenti ma da quello che ho letto sul libro i costruttori delle classi abstract vengono invocati dai costruttori delle classi che le estendono per inizializzare la parte comune di rappresentazione, giusto?
Allora quì (nel costruttore di SortedIntSet):


public SortedIntSet(){ // COSTRUTTORE
els = new OrderedIntList();
}

dove cavolo viene invocato il costruttore della classe padre IntSet? Lo fà in automatico senza dover specificarlo? potevo anche metterci dentro super()?

3) Avrei potuto non usare la classe padre abstract (IntSet) ed al posto di questa usare un'interface IntSet senza NESSUNA RAPPRESENTAZIONE (la variabile dimensione) ed implementare vari sottotipi di IntSet tra cui ad esempio il SortedIntSet visto prima ed un ConstantIntSet ognuno con una sua propria rappresentazione e l'implementazione di tutti i metodi abstract definiti dentro l'interface IntSet, avrebbe avuto più senso o no?

4) [DOMANDA FORSE DELIRANTE] Se proprio avessi voluto usare la classe abstract come ha fatto lui nell'esempio del codice, a questo punto non sarebbe stato meglio dichiarare private la variabile di istanza dimensione (nella classe abstract) e poi prevedere in tale classe un metodo abstract che mi faceva accedere a tale variabile (così tale metodo era visibile anche nelle classi figlie)...cambiava qualcosa o no?

Grazie
Andrea

Energy++
16-05-2009, 20:31
Ciao,
stavo vedendo un esempio di classe Abstract sul mio libro...ma sinceramente mi pare un po' una porcata come viene usata in questo caso...mi dite se oggettivamente sono cose da evitare o se invece non ho capito bene io?

Praticamente ho una classe astratta IntSet che mi fornisce una rappresentazione parziale di un insieme di interi e l'unica variabile di istanza è la variabile protected dimensione che indica la dimensione di tale insieme di interi.

Poi estendo tale classe abstract mediante la sottoclasse SortedIntSet che rappresenta un insieme di interi ordinati e che usa come variabile di istanza una OrderedIntList (una classe che mi rappresenta liste di interi ordinate).
In tale sottoclasse viene fornita la rappresentazione vera e propria del tipo di dati (che nella classe astratta non veniva fornita perchè poi magari potrei avere altre estensioni di IntSet che la implementano in altro modo...tipo ad esempio un'altra sottoclasse ConstantIntSet che rappresenta insiemi di interi di dimensione costante).

La variabile di istanza dimensione della superclasse è stata definita protected così quando ad esempio aggiungo con il metodo insert() o rimuovo con delete() un elemnto ad OrderedIntList posso accedere alla variabile protected dimensione ed aggiornarla.
Ma francamente mi pare un po' una porcata dichiarare tale variabile protected per 2 motivi:

1) Se cambio l'implementazione della superclasse devo cambiare l'implementazione delle varie sottoclassi.
2) Motivi di sicurezza perchè è visibile in tutto il package e qualsiasi metodo definito nel package potrebbe andare a modificarla.

Che mi dite in proposito? C'ho ragione io o mi sfugge qualcosa?



si, credo sarebbe stato meglio dichiarare la variabile come private e poi creare dei metodi di accesso e modifica (set, get)



Il codice d'esempio del libro (parzialmente implementato) è il seguente:


cut..



cut..


Poi ho qualche domanda teorica:

1) Estendendo IntSet la variabile protected dimensione viene ereditata in SortedIntSet...se si...perchè allora devo dichiararla protected per potervi accedere dalla classe figlia? Se era dichiarata private e viene ereditata perchè non ci si accede automaticamente?



le variabili e i metodi dichiarati private non hanno visibilità fuori dalla classe di appartenenza:

Accesso privato: si può accedere solo dall’ambito della stessa classe
Accesso pubblico: Completamente disponibile per qualsiasi altra classe che voglia farne uso
Accesso protetto: visibile dalle sottoclassi e nello stesso package
Accesso di default: visibile nello stesso package


2) Il costruttore della classe abstract IntSet non viene mai invocato dagli utenti ma da quello che ho letto sul libro i costruttori delle classi abstract vengono invocati dai costruttori delle classi che le estendono per inizializzare la parte comune di rappresentazione, giusto?
Allora quì (nel costruttore di SortedIntSet):


public SortedIntSet(){ // COSTRUTTORE
els = new OrderedIntList();
}

dove cavolo viene invocato il costruttore della classe padre IntSet? Lo fà in automatico senza dover specificarlo? potevo anche metterci dentro super()?


la classe IntSet ha un costruttore senza parametri che viene richiamato in modo implicito dai costruttori delle varie classi derivate. In caso di un costruttore con parametri, la sua invocazione deve essere invece esplicita con super()

Dimension7
16-05-2009, 22:21
Ti è stato già risposto, comunque aggiungo alcune precisazioni:

2)Come dice Energy++ il costruttore viene richiamato implicitamente nei costruttori delle classi derivate: per essere più precisi, questo valer per ogni classe derivata, a prescindere dal fatto che la classe padre sia abstract o meno. Se non ci scrivi niente, il costruttore della classe derivata si comporta come se nella prima riga avesse "super()", se vuoi usare un costruttore diverso da quello a zero argomenti puoi farlo ma dev'essere sempre la prima istruzione del costruttore.

3)Dipende sempre da ciò che ti serve: la classe astratta in genere serve quando si ritiene che alcuni metodi saranno uguali per tutte le classi derivate, mentre altri saranno in comune, quindi saranno dichiarati nella classe astratta. Invece l'interfaccia da un'idea un po' più generica delle funzioni, tra virgolette potremmo dire che sono tutte astratte...
Altra caratteristica è che per usare le classi astratte devi ereditarle (o estenderle, se preferisci dire così), mentre le interfacce si implementano: in Java si può ereditare solo da una classe, ma si posso implementare più interfacce.

4)Come facevi a mettere un metodo abstract che si riferiva alla variabile privata? Essendo abstract non ha corpo, quindi non sai come usarlo, devi implementarlo nella classe figlia... non penso funzionerebbe.
Ora non ricordo precisamente, comunque si usa protected per le classi che dovranno essere derivate per un fatto di semplicità, per usare una variabile private nella classe abstract poi avresti dovuto prevedere un metodo getter concreto nella classe stessa. Ma comunque una variabile protected può essere vista solo nello stesso package, quindi si può optare per la creazione di un package piccolissimo, magari costituito solo dalla classe in questione, ed ecco che la variabile sarà accessibile solo a chi eredita dalla classe.