Newsgroup: it.comp.java
Titolo: metodi Object:se non li voglio?

ciao a tutti,
un quesito su java venuto fuori su una ML di programmazione:
come e' noto Object mette automaticamente a disposizione una serie di metodi
che vengono automaticamente ereditati.
ma se io non voglio che la mia classe implementi questi metodi come faccio?
ovviamente voglio che nessuno li possa usare, quindi non basta "trascurarli"
e lasciare l'implementazione di default...
l'unico modo che conosco e' effettuare l'over-ride e non chiamare super().
e' giusto no?
altri suggerimenti?
Grazie!
--
Ciao by Allanon


In c++ se fai overriding come private non ti ci fa + accedere. Non so se in
java una cosa del genere si può fare, sinceramente non mi sono mai posto il
problema neanche in c++..

 problema neanche in c++..
Per curiosità ho provato in java, non funziona, dice:
"Bee.java": Error #: 458 : method toString() in class test.Bee cannot
override method toString() in class java.lang.Object with weaker access
privileges, was public at line 10, column 18

super(). e' giusto no?
No. La tua classe implementera' questi metodi - con implementazioni
vuote quando possibile (il tipo di ritorno e void) o con valori
di default.
Inoltre, in java non e' possibile fare l'override di un metodo con un
livello di protezione piu' restrittivo - per il principio di
sostitubilita' di Liskov: un parolone per dire che dove c'e' un'istanza
di una classe base puoi sempre sostituire un'istanza di una sua classe
derivata - principio enunciato (in forma piu' rigorosa :) dalla signora 
Liskov, appunto. 
Quindi, se quello che vuoi e' che il compilatore ti vieti di usare uno di
quei metodi, non si puo' (e ha poco senso, ma questo e' un altro discorso
:-). 
-- 
Life's something u don't get out alive..
ObjectZone - 
http://space.tin.it/computer/csadun

 :-).
perche' ha poco senso?
nella classe Object c'e' il metodo clone() ad esempio. se io non voglio
farlo clonare come faccio?
ribadisco: override con metodo vuoto?
e le eccezioni? niente neppure quelle, vero? ho fatto una prova e mi dice
che non posso lanciarle...
--
Ciao by Allanon

dice che non posso lanciarle...
Sono stato troppo sintetico. :-) 
Ragioniamo in termini di insieme di metodi esposti da una classe: se 
Object dichiara e implementa un metodo public metodo(), e (come accade 
in Java) ogni classe X deriva da Object, ci sono solo due casi possibili:
    	- o X non fa l'override di metodo() - e, per ereditarieta', 
        espone comunque metodo(); 
      - oppure X ne fa l'override - e anche in questo caso espone
      metodo() 
        (semplicemente, la sua implementazione sara' diversa da quella 
        fornita da Object).
Ora, se capisco bene, tu chiedevi se fosse possibile far si' che
il compilatore intercettasse queste chiamate, aiutando il programmatore
a capire che, secondo il tuo design di X, su X non e' corretto chiamare 
metodo(); e volevi che questo "aiuto" si concretizzasse nella generazione
di un errore a compiletime. 
Questo non e' possibile, dato che per quanto sopra il compilatore
accettera' in ogni caso un'invocazione a metodo(): non c'e' modo di dire
al compilatore "non accettare invocazioni a metodo() su questa specifica 
estensione X di Object". 
Inoltre, questa e' una cattiva idea in partenza, perche' avere questa
possibilita' condurrebbe a gerarchie che potenzialmente possono violare
il principio di Liskov. 
Di per se', questo principio aiuta ad assicurare che l'ereditarieta' sia
usata per creare vere *estensioni* logiche di una classe, e non
semplicemente per riusare parti di implementazioni - che e'
caratteristica di "cattivi" design object oriented.. "cattivi" perche'
_non_ possiedono certe proprieta' desiderabili riguardo a flessibilita',
manutenibilita' e gestione della complessita', che sono alla radice della
stessa esistenza della tecnologia object-oriented rispetto a precedenti
paradigmi. 
In altri termini, un'estensione di Object *e'* un Object - quindi deve
implementare sensatamente la semantica di Object... al minimo, non puo'
avere "meno metodi" di Object.
Nota che questo non e' sufficiente: un programmatore puo' rispettare il
principio di Liskov e fare casini lo stesso.. ad esempio con
implementazioni che rispettano la lettera (il prototipo :-) di un metodo,
ma non il suo spirito (il suo significato, la "semantica").. ad esempio
un metodo 
 public int somma(int b) { return (this.valore -= b); } // (nota il "-=")
e' una buona ricetta verso il disastro :-).
Stesso discorso per i metodi protected - come clone(): classi derivate
non possono "non esporre" questo metodo (alle proprie sottoclassi), nel 
senso che non e' possibile istruire il compilatore in modo che riporti
un errore quando incontra un'invocazione del metodo in una sottoclasse
di Object.
Ora, se il tipo di ritorno di metodo() e' void, puoi farne l'override
con un'implementazione vuota, tipo
 protected void clone() { }
mentre se non lo e', devi usare un valore di ritorno "finto"
 public boolean equals(Object obj) { return false; }
che pero' e' un'approccio tipo quello di "somma" - un programmatore che
usa la *tua* classe sara' facilmente fuorviato a meno che si legga
tutta la documentazione  e/o il codice della tua classe (il che non
avviene mai, naturalmente :-).
Un'alternativa - per i linguaggi che ce le hanno, come Java - e' usare
le eccezioni; e in caso di linguaggi "controvarianti", come Java, l'uso
di quest'alternativa dipende, oltre da te che costruisci la classe 
derivata, dal progettista della classe da cui derivi, che puo' o meno 
aver previsto il caso in cui un'estensione della sua classe (Object, 
nel nostro caso) _non voglia_ esplicitamente rispettare la semantica 
della classe stessa (Object).
Prendi "clone":
 protected void clone() throws CloneNotSupportedException { 
    	throw new CloneNotSupportedException(); 
 }
il designer di Object ha previsto esplicitamente il caso in cui una 
sottoclasse di Object si rifiuti di implementare la semantica di 
clone() - e la lista di eccezioni quindi comprende 
"CloneNotSupportedException".
Per un altro metodo, per esempio "equals", puoi scrivere un override
 public boolean equals(Object obj) {
   throw new UnsupportedOperationException(); 
 
 }
(nota che l'eccezione deriva da RuntimeException ed esiste da JDK1.2:
per JDK precedenti avresti dovuto usare una 
  new RuntimeException("Operazione non supportata");
Entrambe le cose sono, in genere, "male". :-) Principalmente, ancora
perche' permettono di rispettare Liskov nella lettera ma non nello
spirito - portando in men che non si dica a pessimi design; 
secondariamente, perche' (come per "clone") il tuo codice deve usare
implementazioni diverse per ottenere lo stesso effetto logico ("semantica")
in dipendenza *da una classe scritta da qualcun'altro* - generando
inutile confusione. E.. be' ci sono molti altre possibilita' ma andrebbero
illustrate con esempi e ci si metterebbe un'ora. :-)
In generale meccanismi come l'uso "UnsupportedOperationExcetpion"
dovrebbe essere limitato ad implementazioni parziali durante lo sviluppo,
per tecniche di verifica della robustezza via "inoculazione di errori",
eccetera.
Se 1) sai cosa stai facendo; 2) sei sicuro che chiunuque usera' la tua
classe sapra' cosa sta facendo (e questo e' di solito il problema :-)
allora puoi usare queste tecniche. Ma in genere e' una cattiva idea.
Il trucco? Fare i bravi bambini (il software e' uno dei pochi campi in
cui i bravi bambini si divertono di piu', perche' il loro software
funziona e cosi' passano il tempo giocando a Quake invece di inseguire
bugs :) e *implementare correttamente* la semantica di tutte le operazioni
derivate.
In altri termini, *ogni* oggetto ha, da qualche parte, associata una nozione
di uguaglianza: quindi non c'e' ragione al mondo perche' non si debba
fornire un'implementazione corretta di "equals". Se proprio non si vuole far
fatica, l'implementazione fornita da Object (in cui equals corrisponde
con l'identita' tra riferimenti) va benone.
Stessa cosa per "clone", eccetera.


 in Java) ogni classe X deriva da Object,
[cut: molto interessante!]
ti ringrazio per la chiarissima spiegazione.
anche se avevo intuito "a naso" la cosa (Liskov) adesso e' molto piu' chiaro
il discorso...
rimane pero' il "problema" che in java *non* puoi avere delle classi non
clonabili senza fare i cattivi bambini, come dici tu... :-)
questa cosa non "infastidisce" nella programmazione di tutti i giorni,
probabilmente, ma se uno vuole fare una classe riusabile da altri e che non
sia clonabile per qualche motivo deve fare il cattivo bambino :-(
curiosita':
non ti sono mai capitati casi pratici in cui sei stato costretto a fare il
cattivo bambino e quindi usare queste tecniche?
ad esempio mi e' stato fatto notare come la cosa potrebbe essere necessaria
nella creazione di un pattern singleton, nel quale il clone puo' dare dei
problemi...
che ne dici?
--
Ciao by Allanon