II componenti di business (business objects - BO) espongono i loro servizi mediante le relative interfacce. Un business tier formato da piu' BO comporta :
forte accoppiamento (tight coupling) tra client e i BO
accesso complesso e non uniforme alle risorse di business
problemi di performance sulla rete a causa delle complesse e numerose interazioni client - BO
A cosa serve questo pattern
L'intento del pattern Facade è di :
esporre un'interfaccia "a grana grossa"(coarse-grained) unificata e omogenea (e quindi semplificata) del business tier
ridurre il numero di BO esposti al client
ridurre l'accoppiamento tra client e BO
migliorare le performance di rete diminuendo le interazioni remote tra client e BO
astrarre il client dai dettagli implementativi di business
nascondere la complessità delle interazioni e delle dipendenze dei BO
concentrare il security management ed il transaction management sul business tier
Questo si ottiene anteponendo ai BO un EJB di tipo Session il cui compito è interfacciare e gestire i singoli componenti di business.
Nei Sequence Diagram riportati si illustrano le interazioni fra un client e i BO senza una classe Facade:
Figura 1
e con l'utilizzo di una classe Facade :
Figura 2
Motivazione
Il pattern individua nel Session Facade il "Controller" del business tier con il compito di coordinare e gestire le interazioni fra i BO: il Facade diventa il punto ottimale dove gestire il "workflow" di business (interazioni tra BO, gestione delle transazioni, controllo validità dati, …).
Spiegazione del funzionamento
Il Facade disaccoppia il client dalla complessità del business tier esponendone un'interfaccia uniforme. A titolo di esempio si riporta il codice di un client che accede a due diversi EJB:
A parità di funzionalità offerte, l'utilizzo del pattern Facade semplifica il codice del client come mostrato di seguito :
try
{
Context ctx = null;
ctx = new InitialContext();
// Lookup del Façade che gestisce
gli EJB Account e Shopper
Object obj = ctx.lookup(JndiNames.FACADE);
FacadeHome facadeHome =
(FacadeHome)PortableRemoteObject.narrow(
obj,
FacadeHome.class);
Facade facade = facadeHome.create(userid);
facade.addItem(new ProductOM(. . .));
System.out.println("Acquisto possibile.");
}
catch(BuyException be) {
System.out.println("Acquisto # NON
# possibile !");
}
Struttura
Il Facade
Figura 3
Class Diagram
Figura 4
Sequence Diagram
A secondo dello scopo del Facade, l'implementazione può variare dal "semplice passa carte" (delega ai BO la logica di business) al realizzare le regole di business (coordinando i BO necessari).
L'EJB Facade può essere sia di tipo Stateful che Stateless, a secondo della necessità di contenere o meno una stato conversazionale.
Quando si procede all'implementazione di un Facade, è bene tenere presente la granularità che il componente offre al client.
La letteratura indica di non associare un Facade ad ogni singolo use case (grana toppo fine) bensì ad un insieme di use case correlati ottenendo una granularità "piu' grossa".
Di seguito si riporta un esempio di implementazione di un Session Facade di tipo stateful :
public
class FacadeBean implements SessionBean {
/** Reference to the Shopper Stateful EJB */
private Shopper shopper = null;
/** Reference to the Account Entity EJB entity bean
*/
protected Account account = null;
Nel
metodo ejbCreate si crea un Ejb stateful per la gestione
del carrello della spesa (Shopper) e un Entity per la
gestione del conto virtuale dell'utente (Account).
public void ejbCreate(String ID) {
try {
Context ctx = new InitialContext();
Object lookupObject = ctx.lookup(<<JNDI_NAME_SHOPPER>>);
ShopperHome shopperHome
=(ShopperHomePortableRemoteObject.narrow(
lookupObject,ShopperHome.class);
lookupObject = ctx.lookup(<<JNDI_NAME_SHOPPER>>);
AccountHome accountHome = (AccountHome)
PortableRemoteObject.narrow(lookupObject,
AccountHome.class);
this.shopper = shopperHome.create(ID);
this.account = accountHome.findByPrimaryKey(new
AccountPK(ID));
A titolo di esempio si mostrano tre possibili implementazioni dei metodi del Facade :
removeItem: il Facade delega l'operazione all'EJB Shopper
addItem: il Facade implementa la logica di business utilizzando sia dati dell'EJB Shopper che i business data dell'EJB Account
deposit: il Facade implementa le business rules e solo nel caso che siano soddisfatte provvede ad accedere ai business data
public
void removeItem(ProductOM prod)throws BusinessException{
try{
shopper.removeItem(prod);
}
catch(RemoteException re) {
throw new BusinessException(re);
}
}
public void addItem(ProductOM prod) throws BusinessException{
try{
// somma tra il costo del prodotto
e l'attuale ammontare
// della spesa
double totToPay = prod.getPrice()+
shopper.getAmount();
// se il totale è inferiore
dei soldi disponibili
// aggiungo il prodotto al carrello
della spesa
if( totToPay > account.getBalance())
throw new BusinessException(.
. .);
shopper.addItem(prod);
}
catch(RemoteException e) {
throw new BusinessException(e);
}
}
public void deposit(double money) throws BankException
{
try {
if ((money <= 0)||(money
> <<MAX VALUE>>))
throw new BankException("Deposit
["+money+"] NOT allowed !");
// aggiorno il saldo se la cifra
è compresa
// nel range specificato
account.setBalance(account.getBalance()
+ money);
} catch (RemoteException e) {
throw new BankException(e);
}
}
Un caso d'uso
Nell'esempio proposto il Session Facade gestisce un semplice caso di eCommerce "nascondendo" al client la gestione degli EJB Shopper e Account.
Figura 5
Bibliografia e riferimenti
L'archivio zip con gli esempi è scaricabile
[qui](mokapattern_facade.zip).
[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
[EJBA] G.Puliti- Corso di EJB VI parte : un esempio completo, Mokabyte N.51, Aprile 2001
MokaByte®
è un marchio registrato da MokaByte s.r.l.
Java®, Jini® e tutti i nomi derivati sono marchi
registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione
anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it