|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Dec 2003
Messaggi: 458
|
[JAVA]ereditarietà
finora ho utlizzato java per creare delle classi abbastanza semplici che ho utilizzato nelle mie pagine jsp:
una classe che mi genera una password, delle classi(e delle servlet) che mi generano dei file pdf, ecc. approfondendo java ho studiato(per ora in maniera abbastanza generica) l'ereditarietà, il polimorfismo ecc. ecco mi chiedo: in casi come il mio, dove al massimo si tratta di progettini con 4 o 5 classi, conviene(insomma si usa) creare comunque delle classi astratte ed utilizzare l'ereditarietà?? nel senso che a me , in progettini così semplici, non mi sembra che se ne possa trarre un gran beneficio (probabilmente l'inesperienza e l'ignoranza non mi fanno vedere le cose come stanno) aspetto consigli grazie |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Feb 2002
Città: Trento
Messaggi: 962
|
Da un certo punto di vista hai ragione tu, l'ereditarietà è uno strumento potente, ma va usato con criterio, e in progetti "semplici" (non ci sono progetti semplici!
Diverso è il discorso, se tu dovessi decidere di riutilizzare il codice che hai creato per altri progetti: trattandosi, come dici, di componenti estremamente semplici ma fondamentali, è altamente probabile che in futuro tu possa utilizzarli nuovamente. Qualora ciò dovesse accadere, averli strutturati fin da principio sfruttando rigorosamente l'ereditarietà potrebbe giovarti non poco...
__________________
"Et Eärallo Endorenna utúlien. Sinome maruvan ar Hildinyar tenn' Ambar-metta!" -- Aragorn Elessar, Heir of Isildur Mixmar -- OpenSuSE 11.1 on AMD 64 3000+ on DFI LanParty nF4-D | GeForce 6600 GT + Thermaltake Schooner on Samsung 710N Storage -- ( 2 x Hitachi Deskstar 80 Gb + 1 x Hitachi 250 Gb ) = 1 RAID 5 + 1 Storage space LaCie Ethernet Disk Mini 250 Gb | HP - DV2150 EL MILAN CLAN |
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Dec 2003
Messaggi: 458
|
penso d'aver capito cosa intendi.
magari dei metodi sono generici e riutilizzabili in + progetti(faccio un esempio eh) e conviene pertanto scriverli in classi padri. è ovvio che ora, limitandomi ad utilizzare le classi in un singolo progetto, non riesco a vedere l'utilità di tale approccio cmq grazie |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Feb 2002
Città: Trento
Messaggi: 962
|
Certo, oppure potresti voler usare le interfacce anzichè le classi per poter un giorno estendere il tuo progetto con nuove funzionalità non previste, il tutto senza dover riscrivere (idealmente
__________________
"Et Eärallo Endorenna utúlien. Sinome maruvan ar Hildinyar tenn' Ambar-metta!" -- Aragorn Elessar, Heir of Isildur Mixmar -- OpenSuSE 11.1 on AMD 64 3000+ on DFI LanParty nF4-D | GeForce 6600 GT + Thermaltake Schooner on Samsung 710N Storage -- ( 2 x Hitachi Deskstar 80 Gb + 1 x Hitachi 250 Gb ) = 1 RAID 5 + 1 Storage space LaCie Ethernet Disk Mini 250 Gb | HP - DV2150 EL MILAN CLAN |
|
|
|
|
|
#5 | |
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
Il problema ora e' capire quando e' necessario. La regola e' che si eredita' una classe da un'altra nel momento in cui si deve modellare una relazione "is a" ("E' un" in italiano). Questa e' la regola generale. Una regoletta pratica e' usare l'ereditarieta' quando vuoi che un oggetto sia usabile in tutte le condizioni al posto dell'oggetto dal quale deriva; si chiama principio di sostituzione. Non si usa l'ereditarieta' per estendere le funzionalita' di una classe. Esistono tecniche piu' efficaci per risolvere questo problema. Lo so che probabilmente ti hanno detto il contrario all'universita' o a scuola, ti avranno parlato di riutilizzabilita' del codice, di codice generico da estendere, di come l'ereditarieta' sia lo strumento per raggiungere la chimera della totale riutilizzabilita'. Dimenticatene Ti faccio qualche esempio per chiarire il discorso. Immagina una classe astratta (interfaccia in Java) di nome IRunnable, che definisce un metodo astratto run(). Ora immagina di avere una classe Command che esegue un qualche comando, magari in risposta ad un input dell'utente. Ha molto senso che la classe Command erediti dalla classe astratta (interfaccia) IRunnable ed implementi il metodo run() per eseguire un'operazione in risposta all'input dell'utente. Il codice di "dispatch" dei comandi, vedra' oggetti del tipo IRunnable e si limitera' ad eseguire il metodo run(): questa situazione e' un classico esempio di applicazione del principio di sostituzione perche' un oggetto di classe Command puo' essere in tutti gli aspetti usato "come se fosse" di tipo IRunnable. In questa situazione l'Ereditarieta' ha molto senso. Ora immagina di voler implementare una classe Command che al momento di eseguire il comando stampi in un qualche file di log una stringa che rappresenta l'operazione eseguita. Come implementeresti questa classe? 1) Crei una nuova classe LoggedCommand che eredita da Command e prima di eseguire il metodo run() del comando scrive il messaggio di log: Codice:
class LoggedCommand extends Command
{
// ...
void run()
{
logger.print("logging command");
super.run();
}
}
Codice:
void run()
{
if (logger != null)
logger.print("logging command");
// codice di esecuzione del comando
}
Codice:
class LoggingRunnable extends IRunnable
{
IRunnable target;
LoggingRunnable(IRunnable target)
{
this.target = target;
}
void run()
{
logger.print("add logging here");
target.run();
}
}
Ti do' un suggerimento: quando hai da fare una scelta mentre programmi scegli sempre la soluzione che sia "il piu' semplice possibile, ma non piu' semplice" ("As simple as possible, but not simpler"). PS. Scusatemi se ho fatto casino con la sintassi fra Java e C#, ma non ho compilato il codice.
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA |
|
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Dec 2003
Messaggi: 458
|
Quote:
dunque: intanto cosa intendi per 'codice di "dispatch" dei comandi'? poi non ho capito perchè nell'esempio date fatto "l'Ereditarieta' ha molto senso"; per quanto riguarda l'indovinello ( la terza soluzione mi sembra forse la più elastica( e quindi la preferisco alla prima) perchè consente di passare a LoggingRunnable altri eventuali oggetti (nel senso di altre classi che estendono IRunnable ) tieni conto che sono andato molto a intuito, è la prima volta che ragiono su cose simili cmq grazie |
|
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Dec 2003
Messaggi: 458
|
pensandoci bene posso raffigurarmi il perchè nel tuo esempio(magari estendendolo unpo') l'ereditarietà ha una certa importanza
|
|
|
|
|
|
#8 | ||
|
Senior Member
Iscritto dal: Oct 2002
Città: San Jose, California
Messaggi: 11794
|
Quote:
Nell'esempio che ho fatto (IRunnable e Command), l'ereditarieta' ha molto senso perche' un oggetto di tipo Command puo' essere usato ovunque un oggetto di tipo IRunnable puo' essere usato. In altre parole puoi sempre ignorare il fatto che un oggetto sia di tipo Command e usarlo esattamente come se fosse di tipo IRunnable. Quote:
La risposta esatta e'... dipende Quale delle tre soluzioni scegli dipende dal problema che devi risolvere e da cio' che stai scrivendo e dalla sua complessita'. Nel 99%, appena ho il problema di dover loggare un comando, io sceglierei la soluzione numero 2 perche' e' la piu' semplice e veloce da implementare. E come ti dicevo prima, devi sempre scegliere la soluzione piu' semplice che risolve il tuo problema salvo complicarla e renderla piu' flessibile solo quando hai bisogno di quella flessibilita'. Ad esempio, la soluzione numero 3, come hai detto giustamente tu, e' piu' flessibile delle altre due, ma questa flessibilita' si paga con una classe in piu' da scrivere (l'Adattatore) e con il suo codice in piu' da scrivere, debuggare, testare e mantenere. Se ti serve solo loggare la classe di tipo Command e nient'altro, scrivere un Adattatore e' un peso che ti porti dietro nel design inutile perche' non stai sfruttando la flessibilita' che ti garantisce, ma, presumibilmente, aspetti di poterla sfruttare in seguito caso mai ce ne fosse bisogno. Ma nel frattempo paghi il costo e quel momento in cui ti serve la flessibilita' potrebbe non arrivare mai (e di solito non arriva). Pagheresti in anticipo dei soldi per un oggetto che magari potrebbero darti in seguito (o magari no)? Ovviamente no, ti terrai quei soldi e li spenderai quando il bene sara' disponibile. Quando programmi il principio e' uguale: non pagare mai il costo associato con un design piu' flessibile se non hai un bisogno immediato e tangibile ed un problema da risolvere. Ritorno all'esempio: nel momento in cui ti servira' loggare comandi di tipo diverso, con la soluzione 2) dovrai aggiungere quell'if in tutte le classi loggabili, potenzialmente molte, una soluzione chiaramente non ideale. Quando sarai in quella situazione ed avrai quella necessita' (se l'avrai), potrai riorganizzare il codice (refactoring) e spostare la logica di logging in una classe Adattatore. Applicherai quello che in gergo si definisce "Muovere l'Embellishment (Abbellimento) in un Adapater (Adattatore)". Fino a quel momento l'if (soluzione 2) risolve bene il problema ed e' la soluzione piu' semplice. La semplicita' e' il primo valore che devi seguire quando programmi. Perche' la soluzione 3 e' preferibile alla 1? Qui entra in gioco l'esperienza. Dall'esperienza io so che creare una classe LoggingCommand ereditata da Command puo' portare a situazioni in cui e' necessario avere un tipo di comando particolare che puo' essere loggato o meno, con conseguente esplosione nel numero delle classi. Da qui all'avere classi tutte del tipo NotLoggingSpecificCommand e LoggingSpecificCommand il passo e' brevissimo e questa situazione diventa velocemente molto complicata da gestire. L'esperienza e la ricerca di semplicita' mi dicono che se avessi bisogno di piu' flessibilita' la soluzione 3 e' preferibile alla 1. In sintesi: l'ereditarieta' e' uno strumento potete ma che va usato con molta attenzione, perche' puo' portare notevoli complicazioni ed un design, in definitva, peggiore. Eredita solo quando ti e' strettamente necessario, all'inizio eredita' solo nel caso in cui ti ho detto qui, quando puoi applicare il principio di sostituibilita'.
__________________
"We in the game industry are lucky enough to be able to create our visions" @ NVIDIA |
||
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Dec 2003
Messaggi: 458
|
appena posso ci do un occhio
grazie |
|
|
|
|
|
#10 | ||||
|
Senior Member
Iscritto dal: Dec 2003
Messaggi: 458
|
Quote:
Quote:
); un esempio che mi sembra più appropriato è:ho una classe Programma.java che chiama un metodo Distruggi(IRunnable iRun) poi ho varie classi che estendono IRunnable : Command,Command2,ecc. ecco a seconda di quale classe(sto pensando ad esempio ad un parametro che viene passato dall'utente di volta in volta, un parametro che indica appunto la classe) passi a Distruggi() questo metodo si comporta in maniera differente. così mi spiego il perchè ho usato l'ereditarieta' (so che è un esempio unpo' del c****) ma spero tu abbia capito Quote:
Quote:
ci sono varie classi : Command,Command1 ecc.; alcune vanno "loggate", altre no. se uso il metodo 1 dovro' costruirmi tanti LoggedCommand/NonLoggedCommand quanti sono le classi Command mentre se uso il metodo 3 mene basteranno 2 di classi. è così? grazie di tutto, ho dato un occhio al tuo link e ti dico che durante la messa del mio matrimonio si ascolteranno non solo Fugazi ma anche S.Youth, Wire, Girls VS Boys,ecc.ecc Ultima modifica di prazision : 18-04-2005 alle 21:44. |
||||
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 04:14.











); un esempio che mi sembra più appropriato è:








