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]
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.
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:
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 = 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 =
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 {
private Account account = null; // Remote reference dell'Entity EJB Account
. . .
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;
// realtivi 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 = 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.
Allegati
I sorgenti sono disponibili qui
**
<< INSERIRE LINK a moka_pattern.zip >>
**
<< INSERIRE LINK a moka_pattern.zip >>
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
