MokaByte Numero 29  - Aprile 1999
Il pattern Memento
la pratica
di
Andrea Trentini
Come realizzare  la persistenza degli oggetti: 
esempi di codice e considerazioni



Dopo qualche cenno teorico di Lorenzo Bettini, eccovi l'atteso codice. 
Realizzeremo una classe che si occupa della memorizzazione di oggetti  memorizzabili" (la ripetizione è d'obbligo ;-)
Al solito, qui trovate il sorgente.
L'esigenza
L'esempio che vi propongo è tratto da un prodotto che stiamo realizzando in università. Tale prodotto NON usa un database per la memorizzazione delle informazioni (eresia! ;-) ma si basa sull'uso estensivo della persistenza degli oggetti attraverso il pattern memento.
La nostra esigenza principale è proprio quella di non vincolare l'utilizzo di un database, ma di realizzare un prodotto 100% "pure java". Questo anche se esistono db "pure java" (vedi IDB)... il fatto è che usando un db bisogna cominciare a scrivere SQL che non è il nostro linguaggio preferito... ;-) inoltre NON necessitiamo di query complicate, infatti in realtà abbiamo giusto bisogno di "salvare lo stato di alcuni oggetti importanti".

Come abbiamo usato il memento
Se date un'occhiata allo schema delle classi potrete notare quali sono i nostri "oggetti" principali (che in realtà per ora sono definiti in forma di interfaccia):

  • PersistentiI

  • Ogni oggetto che voglia essere salvato dovrà implementare questa interfaccia a lui NON interessa come e dove verranno salvati gli stati che lo rappresentano
  • StateI

  • Questi invece saranno gli oggetti da usare come Memento, cioè quelli che incapsuleranno l'informazione estratta dal PersistentI a lui NON interessa chi è l'oggetto che rappresenta, nè dove e come viene salvato 
  • StorageI

  • queste saranno tutte le classi capaci di gestire la memorizzazione da qualche parte (di solito su disco)  a lui NON interessa da dove arrivano gli stati da salvare 
Il meccanismo è semplice: un oggetto persistente sa come generare un oggetto (il memento appunto) che racchiude l'informazione significativa del proprio stato corrente e sa come assorbire un oggetto (ancora un memento) per reinizializzarsi.
Se si vuole salvare lo stato di un oggetto persistente (PersistentI) basta chiedergli di generare un memento (StateI) chiamando il metodo spawnState(), mentre se si vuole reinizializzarlo basta fornirgli un memento (StateI) chiamando il metodo absorbState(StateI).
Lo StorageI ci serve per gestire in qualche modo la memorizzazione degli stati degli oggetti. E' normalmente chiamato Caretaker.
 
 

Un'ipotesi di funzionamento
Facendo finta di avere già una implementazione dei tre ruoli (oggetto da salvare, stato e caretaker) potremmo eseguire un brano di programma così fatto:
 

PersistentI p;
StorageI s;
... //creazione oggetti;

s.saveState(p.spawnState());

// una qualche chiamata di metodo che CAMBIA lo stato di p
p.metodo();

// se ora voglio tornare allo stato precedente di p
// (quello che ho salvato)
p.absorbState(s.retrieveState("ID dell'oggetto"));


NOTA: considerate le interfacce come se fossero classi implementate. 
In realtà le classi implementate le abbiamo ;-)
Guardate l'albero delle classi. Abbiamo un TestPersistent che realizza un generatore di stati (e che è anche stato di se stesso). Abbiamo un SerialStorage che realizza il caretaker. 
 
 

Come usare l'esempio
Ovviamente bisogna compilare tutto il sorgente... ;-)
Vi consiglierei di generare anche la documentazione e di scorrerla...
Create una directory vuota di nome "storage" nella dir corrente (dove avete i .class), sarà la dir in cui verranno salvate le immagini degli oggetti.
Se ora (da prompt) lanciate:
java Main >out.html
otterrete un output (su file html) simile, anzi identico, a questo. Come vedete, dopo aver cambiato lo stato dell'oggetto possiamo ancora ritornare al vecchio valore semplicemente recuperando dallo Storage lo stato precedentemente salvato.
 
 

Che mi serve un oggetto "stato di se stesso" ?
La domanda in realtà è mal posta, bisognerebbe domandarsi come mai fare tutto 'sto giro (estrarre lo stato, passarlo al caretaker che poi lo salva) se tanto uso l'oggetto stesso come stato.
In effetti se ci limitassimo a questa situazione avrebbe poco senso. In realtà questo meccanismo ci permette di introdurre nel sistema oggetti che non sono state di se stessi e di farli trattare dagli stessi caretaker. Vediamo come... provate a guardare Main.java, vedete che uso due tipi di oggetti persistenti e UN SOLO storage? Ho infatti sfruttato il meccanismo di "separazione dei compiti" fra i ruoli del pattern memento per poter aggiungere funzionalità a posteriori (infatti la classe TestPersistentProp l'ho aggiunta dopo aver fatto tutte le prove, quando avevo finito tutto).

Alla prossima...
... stesso BatSito (hoops!) ...
Come al solito vi esorto a farmi domande e commenti, sia direttamente. che su JAVA-IT.

 


MokaByte Web  1999 - www.mokabyte.it
MokaByte ricerca nuovi collaboratori. 
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it