Newsgroup: it.comp.java
Titolo: Serializzazione "parziale"

  Salute a tutti.
Siccome questo è il primo messaggio che invio a questo newsgroup mi
presento:
sono uno studente di 23 anni e sono al primo anno fuori corso di Fisica,
a circa due mesi ho iniziato a studiare il Java per conto mio, visto
che - salvo scegliere un indirizzo specifico - in facoltà non si studia
per nulla l'informatica.
  E ora passiamo al problema concreto:
il "pacchetto" - in italino si usa questo termine? - che sto sviluppando
è composto fondamentalmente da due gruppi di oggetti:
- uno contenente oggetti che hanno riferimenti incrociati con uno o più
altri oggetti dello stesso gruppo, ma non con altri oggetti al di fuori
del gruppo. (Gruppo A)
- un altro contenente oggetti che fanno riferimento ad oggetti del loro
gruppo e/o del gruppo A. (Gruppo B)
Gli oggetti del gruppo A non cambiano praticamente mai stato (sono
simili a dei dati che vengono caricati ad inizio programma, ma con molte
relazioni interne), viceversa quelli del gruppo B cambiano spesso stato,
compresi i riferimenti agli oggetti dello stesso gruppo e del gruppo A.
Vista la situazione mi sarebbe necessario salvare gli oggetti del gruppo
B frequentemente, e la serializzazione mi è sembrata la soluzione
migliore - anche se non ne so molto -, ma salvare ogni volta anche gli
oggetti del gruppo A sarebbe uno spreco.
Gli oggetti del gruppo A devo salvarli di certo, ma basta farlo
raramente (anche solo in occasine degli aggiornamenti del programma, o
per l'aggiunta di altri dati).
Io ho pensato ad alcune soluzioni - probabilmente abbastanza stupide
viste la mia scarsa conoscenza dell'argomento -, ma ho trovato per
ognuna qualche controindicazione:
  Soluzione 1:   in writeObject degli oggetti del gruppo B che fanno
riferimento ad oggetti del gruppo A, invece di scrivere l'oggetto a cui
si fa riferimento (oggetto del gruppo A) scrivere il suo hashcode, ed in
fase di caricamento (readObject) dato l'hashcode riottenere l'oggetto
chiedendolo ad un unico contenitore con dentro tutti gli oggetti del
gruppo A.
Gli oggetti del gruppo A invece vengono serializzati per conto loro.
  Problemi:   non so molto riguardo agli hashcode, né su come vengano
calcolati, ma a quanto ho capito non sono univoci ed ho letto che non è
garantita la loro costanza da esecuzione ad esecuzione: quindi quando
ricarico i dati salvati il giorno prima potrei trovarmi con dei
riferimenti ambigui o, ancora peggio, che non corrispondono.
  Soluzione 2: simile alla precedente, ma invece dell'hashcode usare un
nome come chiave univoca, ed eventualmente mettere tutti gli oggetti del
gruppo A in un'unica Hashtable.
  Problemi:   oltre al problema dell'aumento di dimensione degli oggetti
(soprattutto quelli molto piccoli e numerosi), c'é il problema che ogni
volta che aggiungessi oggetti al gruppo dovrei inventarmi dei nomi e
controllare di non averli già usati. Quest'ultimo problema si
aggraverebbe se lasciassi aggiungere oggetti al gruppo A (che sono un
po' i dati di partenza del programma) ad altri.
  Abbozzo di soluzione 3: salvare i dati del gruppo A in uno o più
files, al cui interno non ci sono nomi doppioni, ed aggiungere come
chiave, oltre al nome dell'oggetto, anche quello del file a cui si
riferisce.
Forse c'è una soluzione molto più semplice che non vedo per la mia
ignoranza, e quindi mi sto complicando la vita inutilmente; forse usare
un database per il gruppo A sarebbe più comodo, ma io non sò
praticamente nulla a riguardo.
Spero che si capisca quello che ho scritto, e mi scusa per la lunghezza
eccessiva.
Spero qualcuno possa darmi qualche suggerimento o dirmi dove andare a
guardare, ma anche una semplice opinione sarebbe molto gradita.
Grazie 1000 in anticipo.

...
    [snip]
Problema interessante.  Puoi usare come "identificatore unico" per
gli oggetti di gruppo A un semplice intero crescente (incrementato
e assegnato ogni volta che crei un oggetto di gruppo A), e tenere gli
oggetti stessi in un semplice array (puoi usare anche HashTable, o
che altro, overridando negli oggetti di gruppo A il metodo di Object
che torna il valore di hash; ma un intero crescente, e un array, pare
di gran lunga la cosa piu` semplice).
In pratica, questo "intero identificatore unico" ti fa da "nome" per
gli oggetti di A, senza nessuno dei problemi che ti darebbe avere
come nome una stringa.
Puoi incapsulare la generazione in una qualche classe apposita.  Se
gli A possono avere una classe base in comune, questo ti risolve
un po' tutto; se no, usa una interfaccia (con un unico metodo per
accedere all'UID, Unique-IDentifier) e magari incapsula la generazione
in una classe-fabbrica ("factory") con vari metodi opportuni.
Il miglior testo sulle "strutture di progetto" nella programmazione a
oggetti resta Gamma, et al, "Design Patterns", Addison-Wesley 1996;
ma ti consiglio caldamente anche "Thinking in Java", Bruce Eckel,
gratuitamente scaricabile da 
www.BruceEckel.com
 -- un ottimo testo
di Java, menziona anche alcuni concetti di design patterns, oltre a vari
temi avanzati come serializzazione ecc ecc.
Alex

 praticamente nulla a riguardo.
al di là dell'interesse specifico del tuo problema, tra l'altro da te
formalizzato in maniera esemplare, credo che questa sia decisamente la
soluzione più sensata. Magari non la più veloce nel breve periodo, ma
stai pur certo che le conoscenze acquisite ti torneranno utili sempre,
anche professionalmente... puoi usare JDBC (ora una core API) che mappa
su ODBC e ti permette di accedere praticamente a qualsiasi DB.
So per certo che esistono dei DB freeware, anche 100% Java, ma ora non
mi ricordo nomi (mySQL?) e tanto meno URL... io per lavoro sono
costretto a usare Access e al più Oracle.
ciao
S


Grazie per il suggerimento: ovviamente la soluzione più semplice mi era
sfuggita.
Ultimamente ho semplificato la struttura del programma, riducendo il gruppo
A a tutti e soli gli oggetti di 7 classi, con rapporti dovuti quasi
esclusivamente a contenitori (spesso array).
C'è voluto del lavoro ma la semplificazione ripaga.
Ho pensato di mettere in atto il tuo consiglio creando una superclasse
astratta comune a queste 7 classi:
public abstract class Dato {
  int universalID;
  public void setUID(int uID) {
   universalID = uID;
  }
  public int getUID() {
   return universalID;
  }
}
Ho poi creato una classe contenitore che contiene direttamente tutti gli
oggetti del gruppo A e serve come supporto per i riferimenti del gruppo B, e
per la serializzazione.
import java.io.Serializable;
public class BancaDati implements Serializable {
 String nome;
 Dato[] dati = new Dato[0];
 int numeroDati = 0;
 int maxUID = 0;
  public String nome() {
   return nome;
  }
  public void aggiungiDato(Dato dat) {
   maxUID++;
    dat.setUID(maxUID);
    // Codice per aggiungere dat a dati
    numeroDati++;
  }
  public void rimuoviDato(Dato dat) {
   rimuoviDato(dat.getUID());
  }
  public void rimuoviDato(int uID) {
   if (uID > maxUID)
    return;
   if (dati[numeroDati-1].getUID()==uID) {
    maxUID = dati[numeroDati-2].getUID();
    }
    else {
     int i;
      for (i=uID-2;i<0;i--) {
       if (dati[i].getUID()<uID)
        return;
       if (dati[i].getUID()==uID)
        break;
      }
      if (i<0)
       return;
      // Codice per rimuovere l'i-esimo Dato
    }
    numeroDati--;
  }
  public Dato trovaDato(int uID) {
   if (uID > maxUID)
    return null;
    for (int i=uID-1;i<0;i--) {
     if (dati[i].getUID()<uID)
      return null;
     if (dati[i].getUID()==uID)
      return dati[i];
    }
    return null;
  }
}
Spero di aver interpretato bene il tuo consiglio.
Grazie anche per i consigli sui testi da consultare: ho già scaricato Think
in Java.
Se qualcuno notasse un errore grossolano nel mio codice, o semplicemente
avesse un consiglio per semplificarlo o migliorarlo gliene sarei grato.
Buon Natale e Felice Anno Nuovo a tuttttti !!!!!!!!!
Alle

Stefano Gaburri wrote:

Credo che tu abbia ragione, anche se il mio tempo libere è piuttosto
scarso. Ti ringrazio comunque per il consiglio e per i riferimenti a cui
appoggiarmi.
Spero di non chiedere troppo, ma ..
ho usato qualche volta Access (l'unico che avevo sotto mano) e qualcosa ho
imparato: ho pensato di creare una tabella per ogni classe in cui riportare
i valori che identificano uno stato, ed aggiungere un chiave per
identificare l'oggetto (non sò se sia o meno il modo corretto), ma ho avuto
molti problemi per quanto riguarda gli array o i contenitori in genere.
Forse una tabella aggiuntiva con 2 colonne: una con la chiave relativa
all'oggetto contenitore e una con la chiave dell'oggetto contenuto (oppure
il dato contenuto in caso di array di tipi primitivi).
Se qualcuno mi può consigliare, sul mio problema, o comunque su dove
trovare notizie e applicazioni riguardanti DBs, possibilmente da scaricare
gratuitamente, sarebbe un bel regalo.
Grazie a tutti e Buon Anno.