Newsgroup: it.comp.java
Titolo: classi con diverse implementazioni

Ho un programma che utilizza una classe X, questa classe pilota un
aggeggio attaccato alla seriale. A seconda dell'aggeggio
l'implementazione cambia.
Il mio obiettivo e' fare in modo che un programma che usa X rimanga
scritto sempre nello stesso modo, ossia istanzio sempre la classe X, e
risieda nel suo bel jar e, a seconda del jar contenente la classe X che
si trova nel classpath, viene usata una implementazione piuttosto che
un'altra. Se cambio l'aggeggio collegato alla seriale mi basta
sostituire il jar X esistente con quello del nuovo aggeggio lasciando
inalterato il jar del programma.
Per ora ho pensato di fare piu' jar con all'interno la stessa classe
realizzata in modi diversi, la via immediata, ma magari esistono modi
piu' "corretti" di fare questo...
Alternativa: file di conf con scritto che implementazione usare pero'
implica che il programma conosca tutte le implementazioni con cui avra'
a che fare e quindi cambierebbe il jar del programma ogni volta che
appare una nuova implementazione.... vorrei evitarlo.
a voi la palla.
ciao
-- 
Seti@Home Java Applets
http://maruko.webhop.net/

 [...]
E' un pattern comunissimo: l'implementazione di una specifica classe
non e' nota fino a runtime.
Si risolve definendo un'interfaccia (che e' quella che il tuo programma 
"vede") e abbinandole una factory che, a runtime, decide che 
implementazione dell'interfaccia creare.
Un modo semplice e' definire una factory una volta per tutte, dotandola di 
opportune proprieta' per poter decidere che implementazione concreta 
cercare (ad esempio, usando una property, o un file di preferenze, 
eccetera). 
Se invece anche il modo e le proprieta' in base a cui la factory crea la 
tua istanza concreta varia di molto (o non e' prevedibile), applichi lo 
stesso meccanismo alla factory stessa, definendo una factory-di-factory (in 
genere questa cosa serve solo per librerie di respiro veramente generale, 
in applicazioni il primo livello di norma basta e avanza).
-- 
Fighting for peace is like fucking for virginity
ObjectZone - 
http://space.tin.it/computer/csadun


Il discorso dell'interfaccia l'ho capito e ci avevo pensato anche se
attualmente estendo una classe astratta (perche' mi andava cosi' non
perche' ho fatto una scelta ragionata, sarebbe interessante conoscere i
problemi che mi potrebbe dare la soluzione con classe astratta)
Forse mi sfugge qualcosa ma come dici tu la factory deve conoscere tutte
le implementazioni  e il problema si e' spostato dal programma alla
factory.
Cerco di essere piu' semplice:
il cliente A ha il programma P collegato all'aggeggio K:
gli fornisco il jar del programma e un jar col "driver" per K.
il cliente vuole usare L al posto di K (stesse funzionalita' diverso
protocollo):
va bene, gli mando L e un jar col "driver" per L che sostituisce quello
per K.
Con la tecnica che suggerisci anche la factory va aggiornata se L non e'
ancora stato implementato e quindi non le e' noto, o sbaglio?
Quindi che faccio? Metto una factory per ogni "driver"? Cosi' pero' si
ricade nel caso che avevo proposto a livello di implementazione del
"driver", ossia una classe con nome comune a tutti i diversi jar.
N.B. non voglio fare un jar con dentro tutti i "driver" possibili. Se
facessi cosi' la storia della factory funzionerebbe perfettamente.


 per K.
Una factory "semplice" funziona bene se i tipo e numero dei parametri 
necessari alla creazione sono costanti tra le varie implementazioni. 
Assumendo questo, mettiamoci nel caso semplice (un'implementazione di 
driver e' sempre costruibile mediante il costruttore di default). 
Ci sono due idee: o l'astrazione e' su cosa cercare (factory) o sul come 
cercarlo (factory di factory).
Un'implementazione semplice della prima, basata su variabili d'ambiente o 
opzioni a linea di comando, puo' essere
- lo script di shell che lancia il tuo programma contiene una cosa tipo
  java -DdeviceName=$(DEVICE_NAME) mio.programma ....
o in alternativa java mio.programma -device $(DEVICE_NAME) o ancora 
accedere direttametne alla variabile d'ambiente DEVICE_NAME mediante 
librerie del caso.
- la factory ha un metodo tipo
public Driver createDriver() {
    	String deviceName=System.getProperty("
device.name
"); 
    	// oppure letto da linea di comando etc
    	String driverClassName="com.my.drivers."+deviceName+"Driver";
    	try {
    	    	return (Driver)Class.forName(driverClassName).newInstance();
    	} catch { ...exception handling... }
}
(chiaramente puoi migliorare enormemente la qualita' della diagnostica in
caso di errore facendo controlli difensivi sull'esistenza della classe,
sul suo tipo, etc, e producendo messaggi appropriati in caso di errori).
Se ti servono parametri, userai un java.lang.reflect.Constructor in modo 
analogo. Se il tipo e numero di parametri cambia, o usi un Object 
perdendo in typechecking (e ogni Driver interpretera' l'Object a modo suo) 
oppure usi un Setup object (cfr. per esempio 
http://sadun-
util.sourceforge.net/api/org/sadun/util/Setup.html
), magari creato con la 
stessa tecnica (nessuno dice che una factory debba creare un solo tipo di 
oggetto).
Se poi addirittura vuoi una cosa tutta automatica, con la factory che 
fornisce ad esempio una lista di tutti i driver installati, ci sono metodi 
un filino piu' costosi ma possibili: un meccanismo simile alle extension 
library (metti i jars coi driver in una particolare directory, e la factory 
ne fa lo scanning e cerca le classi che implementano la tua interfaccia 
Driver); oppure usi una cosa simile a 
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/sadun-
util/Utility%20classes/source/org/sadun/util/SimpleClassPackageExplorer.jav
a


 "driver", ossia una classe con nome comune a tutti i diversi jar.
Correggetemi se sbaglio, ma non è detto che la factory debba utilizzare un
metodo hard coded per determinare la classe da istanziare. Mi spiego: nel
tuo jar puoi aver un file di configurazione (o al limite nel manifest
stesso) che specifica il nome della classe che implementa l'interfaccia X (o
estende la classe astratta X, è indifferente). La factory legge il nome
della classe e con Class.forName("<nome classe>").newIstance(); ne crea
un'istanza che poi restituisce al programma.
Puoi realizzare il tutto con un'architettura plug-in in modo tale che il
programma all'avvio trova il jar specifico per il dispositivo e lo utilizza
(probabilmente avrai bisogno di un classloader idoneo per leggere la classe
di implementazione dal jar plug-in).
HTH
Francesco

 ha scritto nel messaggio
news:ieTOa.158522$Ny5.4...@twister2.libero.it...
