|
Introduzione
In questo articolo si parlerà del pattern Model-View-Control(MVC).
Verrà presentata un'applicazione demo J2EE che
oltre a mettere in pratica il paradigma MVC, mostrerà
un possibile utilizzo dei pattern spiegati nei precedenti
numeri di Mokabyte:
-
Data Access Object Mokabyte N.62-Aprile 2002 [DAO]
- DAO
Factory Mokabyte N.63-Maggio 2002 [FCT]
- SessionFacade
Mokabyte N.64-Giugno 2002 [FAC]
- Business
Delegate Mokabyte N.65-Luglio 2002 [BD]
- Service
Locator Mokabyte N.67-Ottobre 2002 [SL]
- Value
Object Mokabyte N.69-Dicembre 2002 [VO]
- Front
Controller Mokabyte N.70-Gennaio 2003 [FC]

Figura 1 - Struttura dell'applicazione
Demo
(clicca sull'immagine per ingrandire)
A
cosa serve
L'intento
del pattern Model View Control (MVC) è di disaccoppiare
il più possibile tra loro le parti dell'applicazione
adibite al controllo, all'accesso ai dati e alla presentazione.
[MOKASHOP_1].
Questo
approcio porta ad innegabili vantaggi come:
- indipendenza
tra i business data (model) la logica di presentazione
(view) e quella di controllo (controller)
- separazione
dei ruoli e delle relative interfacce
- viste
diverse per il medesimo model
- semplice
il supporto per nuove tipologie di client: bisogna
scrivere la vista ed il controller appropriati riutilizzando
il model esistente
Con
il termine Model si individua la rappresentazione dei
dati dell'applicazione enterprise e le regole di business
con cui tali dati vengono acceduti e modificati.
La View è la vista del modello. Uno stesso modello
può quindi essere presentato secondo diverse
viste.
Il Controller è colui che interpreta le richieste
della view in azioni che vanno ad interagire con il
Model aggiornando conseguentemente la view stessa.

Figura 2 - MVC: schema funzionale
Spiegazione
del funzionamento
Il paradigma Model-View-Control in ottica J2EE può
essere così implementato:
- Model:
componenti EJB che incapsulano la logica applicativa
e implementano l'accesso agli Enterprise Integration
System (DBMS, Host,
).
- Controller:
entità modellabile come Servlet (o JSP) e classi
dette RequestHandler per gestire le richieste dell'utente
- View:
è costituita dalle pagine JSP si occupano di
gestire gli aspetti di rendering (HTML, WML, XML,
ecc.) dei dati applicativi.
Il
WebController è generalmente costituito da una
Servlet che agisce da FrontController [FC] effettuando
sia le operazioni di "controllore" che di
"smistatore" delle richieste proveniente dal
client tier (nell'esempio proposto è la classe
di nome FrontControllerServlet). Il suo compito è
di creare l'opportuna classe RequestHandler (AccountRequestHandler)
per demandare la gestione della specifica richiesta
ed invocare l'opportuna vista (displayAccount.jsp o
error.jsp). Deve quindi informare e aggiornare il Presentation
Model (AccountViewBean), cioè l'insieme dei dati
che vanno a comporre la vista finale per l'utente a
fronte di modifiche che l'operazione di business, invocata
dall'utente ed evasa dal RequestHandler [BD, SL, FACADE],
ha apportato al Business Model (AccountVO). Il Business
Model sono i dati che rappresentano il Model e sono
ritornati dai BO (gli EJB FacadeBean [FAC] e AccountBean
[DAO, FCT]) sotto forma di Value Object o di collezioni
di Value Object [VO].
Nell'esempio proposto si crea un'applicazione basata
sul modello MVC che permette, via Web, di accedere ai
dati di descrizione di un conto corrente.
Si riportano i diagrammi UML relativi all'esempio proposto:

Figura 3 - MVC: Sequence Diagram (parte
I)
(clicca sull'immagine per ingrandire)

Figura 4 - MVC: Sequence Diagram (parte
II)
(clicca sull'immagine per ingrandire)
Presentazione
del codice Java
Nel
metodo doPost() della FrontControllerServlet si legge
il parametro di nome FUNCTION della HTTP Request. Tale
parametro è l'azione richiesta dall'utente.
String
function = request.getParameter("FUNCTION");
L'action
viene usata per richiedere alla classe FactoryRequestHandler
di restituire l'appropriato RequestHandler. Nel caso
in cui l'azione richiesta sia la lettura del conto corrente,
viene creata e restituita dal Factory un'istanza di
classe AccountRequestHandler.
Su tale istanza viene invocato il metodo execute che
permette l'avvio della gestione della richiesta da parte
del RequestHandler
GenericRequestHandler
grh;
grh = FactoryRequestHandler.getRequestHandler(function);
grh.execute(request, response, context);
La
classe AccountRequestHandler all'interno del metodo
execute() ottiene dalla classe factory MvcFactoryBusinessDelegate,
un'istanza d'interfaccia MvcBusinessDelegate che punta
ad un oggetto di classe MvcBusinessDelegateImpl [BD]
MvcBusinessDelegate
proxy;
proxy = MvcFactoryBusinessDelegate.getBusinessDelegate(
this.getClass().getName(),
userid);
mediante
il quale è possibile invocare il metodo di business
getAccount()
AccountVO
model = ((MvcBusinessDelegateImpl)proxy).getAccount();
La
classe MvcBusinessDelegateImpl utilizza nel suo costruttore
la classe MvcServiceLocator che si occupa di localizzare
la Home interface dell'EJB Facade[SL], per poi inizializzare
le proprietà dell'interfaccia remota dell'EJB
public
class MvcBusinessDelegateImpl
implements
MvcBusinessDelegate{
private Facade remote = null;
public MvcBusinessDelegateImpl(String user_id)
throws
BusinessDelegateException{
try {
FacadeHome home = (FacadeHome)MvcServiceLocator.
getHome("MokaFacade");
this.remote = home.create(user_id);
Il
metodo getAccount() della classe MvcBusinessDelegateImpl
agisce da proxy verso l'EJB
public
AccountVO getAccount() throws BusinessDelegateException
{
try
{
return
remote.getAccount();
La
classe Business Delegate disaccoppia il controller AccountRequestHandler
dal model avente come entry point l'EJB Session Stateful
FacadeBean [FAC].
E' il FacadeBean che permette di ottenere il Business
Model richiamando il metodo getAccount() dell'Entity
EJB AccountBean
public
class FacadeBean implements SessionBean {
// Remote reference dell'Entity EJB Account
private Account account = null;
. . .
public AccountVO getAccount() throws BusinessException
{
try{
return this.account.getAccount();
il quale provvede a leggere i business data [FCT,DAO]
public
class AccountBean implements EntityBean {
...
public void setEntityContext(EntityContext
ctx) {
this.dao = MyDaoFactory.getDAO();
...
public AccountOM getAccount() {
return new AccountOM(((AccountPK)ctx.getPrimaryKey()).id,
this.name,
this.email,this.balance);
...
Il
Value Object di classe AccountVO ottenuto rappresenta
di fatto il Business Model
public
class AccountVO implements java.io.Serializable{
private String id=null;
private String name=null;
private String address=null;
private double balance= 0.0;
// relitivi metodi get e set per ciascuna
proprietà
e
viene ritornato al controller AccountRequestHandler
che provvede alla creazione del Presentation Model,
AccountViewBean
view = new AccountViewBean(model);
all'inizializzazione
dell'HTTP Request
request.setAttribute("userAccount",
view);
e
ad impostare la successiva vista da selezionare
this.pageName
= "/jsp/displayAccount.jsp";
La
classe AccountViewBean rappresenta il Presentation Model
che di fatto è un Wrapper del Business Model
public
class AccountViewBean implements java.io.Serializable{
private AccountVO model;
public AccountViewBean(AccountVO value)
{
this.model = value;
}
public String getName(){
return this.model.getName();
}
...
Conclusa l'esecuzione del metodo execute() della classe
AccountRequestHandler, la Servlet provvede ad invocare
la successiva view.
risorsa
= grh.getPageName();
RequestDispatcher rd;
rd = this.getServletContext().getRequestDispatcher(risorsa);
rd.forward(request, response);
La
view in questo caso è rappresentata dalla pagina
displayAccount.jsp che si occupa di leggere il contenuto
del bean di nome userAccount e di classe AccountViewBean
e di formattare il risultato nel modo appropriato
<%@
page import="it.mokabyte.pattern.view.AccountViewBean"%>
<jsp:useBean id="userAccount" class="it.mokabyte.pattern.view.AccountViewBean"
scope="request" />
<html>
<body>
<TR><TD > Name:</TD>
<TD> <jsp:getProperty name="userAccount"
property="name"/></TD></TR>
. . .
Un caso d'uso
Il caso d'uso proposto è un'applicazione J2EE
che si bassa sul paradigma di sviluppo MVC.

Figura 5 - Il caso d'uso
Allegati
I sorgenti sono disponibili qui
Bibliografia
e riferimenti
[MOKASHOP_1] - "MokaShop: come progettare una applicazione
multicanale - I parte" di Giovanni Puliti, MokaByte
60, Febbraio 2002
Alur,Crupi,Malks:
Core J2EE Patterns - Best Practices and Design Strategies
Floyd
Marinescu: EJB Design Patterns - Advanced Patterns,
Processes and idioms
Ed
Roman, Scott Ambler, Tyler Jewell: Mastering Enterprise
JavaBeans
Sun
Java Center J2EE Patterns:
http://developer.java.sun.com/developer/restricted/patterns/J2EEPatternsAtAGlance.html
Sun
blueprints-Design Patterns Catalog:
http://java.sun.com/blueprints/patterns/j2ee_patterns/catalog.html
Gamma,Helm,Johnson,Vlissides:
Design Patterns-Elements of Reusable Object-Oriented
Software
|