Contesto
Le applicazioni client necessitano scambio di dati con
i business objects.
A
cosa serve
L'intento del pattern è di modellare i dati di
business in modo granulare mediante oggetti: i ValueObject.
I Value Object incapsulano la quantità di business
data necessaria per soddisfare le esigenze del client
nel colloquio con l'EJB.
In questo modo si ottiene una visione ad oggetti dei
dati di business ottimizzando il trasferimento remoto
dei dati.
Motivazione
Come ogni pattern ci sono diverse strategie:
- Oggetti
immutabili (i suoi campi sono solo read-only, cioè
solo metodi get) - Value Objects Strategy
- Business
objects che rappresentano strutture dati (metodi get/set)
- Updatable Value Objects Strategy
- Aggregazione
di diversi oggetti immutabili - Multiple Value Object
Strategy
- Aggregazione
di oggetti immutabili reperiti da differenti data
store - Value Object Assembler Strategy
Spiegazione del funzionamento
Si crea e si utilizza un Ejb, sul quale vengono invocati
i metodi per reperire i dati di business.
public
class FacadeTestClient {
. . .
public void test(String userid) {
Context ctx = new InitialContext();
Object obj = ctx.lookup(JndiNames.FACADE);
FacadeHome facadeHome = (FacadeHome)PortableRemoteObject.narrow(obj,
FacadeHome.class);
Facade facade = facadeHome.create(userid);
System.out.println("User account name : "
+ facade.getName());
System.out.println("User account email : "
+ facade.getEmail());
System.out.println("User account balance : "
+ facade.getBalance());
A
parità di funzionalità offerte, l'utilizzo
del pattern Value Object richiede una sola invocazione
remota all'EJB:
public
class FacadeObjectValueTestClient {
. . .
public void test(String userid) {
Context ctx = new InitialContext();
Object obj = ctx.lookup(JndiNames.FACADE);
FacadeHome facadeHome = (FacadeHome)PortableRemoteObject.narrow(obj,
FacadeHome.class);
Facade facade = facadeHome.create(userid);
AccountVO objectValue = facade.getAccount();
System.out.println("User account name : "
+ objectValue.getName());
System.out.println("User account email : "
+ objectValue.getEmail());
System.out.println("User account balance : "
+ objectValue.getBalance());
Usando
accorgimenti di programmazione come il Value Object
si ottimizza il trasferimento delle informazioni al
client evitando di fare viaggiare singolarmente i dati
applicativi (nell'esempio sono i dati name, email e
balance).
Figura
1 - Funzionamento senza ValueObject
Figura
2 - Funzionamento con ValueObject
Struttura
Figura
3 - Class
Diagram
Un
caso d'uso
L'EJB Facade presentato in [FACADE] piuttosto che restituire
i singoli dati dell'Entity Bean Account
public
class FacadeBean implements SessionBean {
// Remote reference to the Entity EJB Account
private Account account = null;
. . .
// <<property name>> è il nome della
// proprietà dell'Entity EJB (name, email, balance)
public double get<<property name>> () {
try {
return account.get<<property
name>>();
} catch (java.rmi.RemoteException e) {
throw new BusinessException("Exception
reading property <<property
name>> : " + e);
}
}
mette
a disposizione un metodo di business che crea un Value
Object, lo popola "accorpando" i dati prelevati
dall'Entity e lo restituisce:
public
class FacadeBean implements SessionBean {
// Remote reference to the Entity EJB Account
private Account account = null;
...
public AccountVO getAccount() throws BusinessException
{
try{
AccountVO
objectValue;
objectValue
= new AccountVO(this.account.getName(),
this.account.getEmail(),
this.account.getBalance());
return
objectValue;
} catch (java.rmi.RemoteException
e) {
throw new BusinessException("FacadeBean
getBalance()
failed:
" + e);
}
}
Il
Value Object è costituito dalla classe AccountVO,
che è una classe Java serializzabile con gli
opportuni metodi get:
public
class AccountVO implements java.io.Serializable{
private String name=null;
private String address=null;
private double balance= 0.0;
public AccountVO(String nm, String add, double bal)
{
this.name = nm;
this.address = add;
this.balance = bal;
}
//
Accessors
public String getName(){return this.name;}
public String getAddress(){return this.address;}
public double getBalance(){this.balance;
}
}
Il
trasferimento dati tra l'EJB Facade e l'Entity Account
può essere ulteriormente ottimizzato applicando
nuovamente il pattern Value Object analogamente a quanto
fatto per la comunicazione tra client e EJB Facade.
L'Entity Account espone un nuovo metodo getAccount()
che restituisce un Value Object AccountVO.
public
class AccountBean implements EntityBean {
private double balance;
private String name;
private String email;
...
public AccountVO getAccount() {
AccountVO objectValue = new
AccountVO(id, this.name,this.email,this.balance);
return objectValue;
}
...
}
In
questo modo il Facade EJB non invoca piu' i metodi getName(),
getEmail() e getBalance(), bensì il solo metodo
getAccount():
public
class FacadeBean implements SessionBean {
private Account account = null;
. . .
public AccountVO getAccount() throws BusinessException
{
try{
return this.account.getAccount();
. . .
<<INSERIRE
QUI IMMAGINE 4>>
Risorse
L'esempio
è scaricabile qui
Bibliografia
e riferimenti
[FACADE]
S.Rossini, L. Dozio - "J2EE Patterns - Il pattern
facade", Mokabyte N.64 Giugno
[Gof] Gamma,Helm,Johnson,Vlissides:Design Patterns-Elements
of Reusable Object-Oriented Software
[J2EE] Alur,Crupi,Malks : Core J2EE Patterns - Best
Practices and Design Strategies
[SJP] Sun Java Center J2EE Patterns:
http://developer.java.sun.com/developer/restricted/patterns/J2EEPatternsAtAGlance.html
[BPP] Sun blueprints-Design Patterns Catalog :
http://java.sun.com/blueprints/patterns/j2ee_patterns/catalog.html
|