Zona HTML Zona Java Zona PHP Zona ASP Zona Bases de datos
Inicio > Tutoriales > Lenguajes orientados a objeto > Java > J2EE > Catálogo de Patrones de Diseño J2EE. I.- Capa de Presentación
-Tutoriales

Catálogo de Patrones de Diseño J2EE. I.- Capa de Presentación


View Helper

. Contexto

El sistema crea el contenido de la presentación, lo que requiere el procesamiento de datos de negocio dinámicos.

. Problema

Los cambios en la capa de presentación ocurren muy frecuentemente y son difíciles de desarrollar y mantener cuando la lógica de acceso a los datos de negocio y la lógica del formateo de la presentación se mezclan. Esto hace el sistema menos flexible, menos reutilizable, y generalmente menos adaptable a los cambios.

Mezclar la lógica de negocio y de sistema con el procesamiento de la vista reduce la modularidad y también proporciona una pobre separación de los roles entre los equipos de producción Web y de desarrollo de software.

. Causas

  • Los requerimientos de asimilación de datos de negocio no son triviales.
    • Embeber la lógica de negocio en la vista promueve un tipo de reutilización del tipo copiar-y-pegar. Esto causa problemas de mantenimiento y errores porque una pieza de lógica se reutiliza en la misma vista o en otra diferente simplemente duplicándola en la nueva localización.
    • Es deseable promover una separación limpia de labores teniendo diferentes individuos cumpliendo los roles de miembros de un equipo de desarrollo de software y de producción Web.
    • Una vista comúnmente se utiliza para responder a una petición de negocios particular.

. Solución

Una vista contiene código de formateo, delegando sus responsabilidades de procesamiento en sus clases de ayuda, implementadas como JavaBeans o etiquetas personalizadas. Las clases de ayuda o helpers también almacenan el modelo de datos intermedio de la vista y sirven como adaptadores de datos de negocio.

Hay varias estrategias para implementar el componente de la vista. La estrategia JSP View siguiere utilizar una JSP como el componente vista. Esta es la estrategia preferida, y es la que se utiliza más comunmente. La otra estrategia principal es la estrategia Servlet View, que utiliza un servlet como la vista.

Encapsular la lógica de negocio en un helper en lugar de hacerlo en la vista hace que nuestra aplicación sea más modular y facilita la reutilización de componentes. Varios clientes, como controladores y vistas, podrían utilizar el mismo helper para recuperar y adaptar estados del modelo similares para su presentación en varias vistas. La única forma de reutilizar la lógica embebida en una vista es copiando y pegando en cualquier lugar. Además, la duplicación mediante copiar-y-pegar hace que un sistema sea difícil de mantener, ya que necesitamos corregir en muchos sitios el mismo error potencial.

Una señal de que podríamos necesitar aplicar este patrón al código existente es cuando el código scriptlet domina en la vista JSP. Ya que el objetivo general cuando se aplica este patron, es el particionamiento de la lógica de negocio fuera de la vista. Mientras alguna lógica está mejor cuando se encapsula dentro de objetos helper, otra lógica está mejor situándola en un componente centralizado que se sitúa delante de las vistas y los helpers -- esta podría la lógica que sea común entre varias peticiones, como los chequeos de autentificación o servicios de logs, por ejemplo.

Si no se emplea un controlador separado en la arquitectura, o si no se utiliza para manejar todas las peticiones, entonces el componente vista se convierte en el punto de contacto inicial para manejar algunas peticiones. Para ciertas peticiones, particularmente aquellas que implican un procesamiento mínimo, este escenario funcionará bien. Típicamente, esta situación ocurre cuando páginas que están basadas en información estática, como la primera de un conjunto de páginas que se servirán a un usuario para obtener alguna información. .

El patrón View Helper se enfoca en recomendar formas de particionar las responsabilidades de nuestras aplicaciones.

. Estructura

Abajo podemos observar el diagrama de clases que representa el patrón View Helper.

. Participantes y Responsabilidades

La siguiente figura muestra el diagrama de secuencia que represetna el patrón View Helper. Normalmente un controlador media entre el cliente y la vista. Aunque en algunos casos, no se utiliza un controlador y la vista se convierte en el punto de contacto inicial para manejar peticiones.

Como se ha podido observar en el diagrama de clases, podrían no haber helpers asociados con una vista. En este caso simple, la página podría ser completamente estática o incluir una muy pequeña cantidad de scriptles. Este escenario se describe en el siguiente diagrama de secuencia:

. View

Una vista representa y muestra información al cliente. La información que se utiliza en un display dinámico se recupera de un modelo. Los helpers soportan vistas encapsulando y adaptando un modelo para utilizarlo en un display.

. Helper

Un helper es el responsable de ayudar a la vista o al controlador a completar su procesamiento. Así los helpers tienen numerosas responsabilidades, incluyendo la obtención de los datos requeridos por la vista y su almacenamiento en el modelo intermedio, en cuyo caso algunas veces nos podemos referir al helper como un Bean de Valor. Además, los helpers podrían adaptar este modelo de datos para que los utilizara la vista. Los helpers pueden servir peticiones de datos desde la vista simplemente proporcionando acceso a los datos o fomateando los datos como contenido Web.

Una vista podría trabajar con cualquier número de helpers, que normalmente están implementados como JavaBeans (JSP 1.0+) y etiquetas personalizadas (JSP 1.1+). Además, un helper podría representar un objeto Command o un Tranformador XSL, que se utiliza en combinación con una hoja de estilo para adaptar y convertir el modelo en el formato apropiado.

. ValueBean

Un Bean de Valor es un otro nombre para un helper que es responsable de contener el estado del modelo intermedio para que lo utilice una vista. Un caso típico, es el que tiene un servicio de negocio que devuelve un bean de valor en respuesta a esta petición. Este caso, el Bean de valor cumple el rol de un objeto Transfer.

. BusinessService

El servicio de negocio es un rol que cumple el servicio al que está accediendo el cliente. Típicamente, se accede al servicio de negocio mediante un Delegado de Negocio. El rol del delegado de negocio es proporcionar control y protección para el servicio de negocio (podremos ver el patrón Business Delegate más adelante).

. Estrategias

. JSP View

La estrategia de Vista JSP sugiere la utilización de una JSP como el componente vista. Aunque semánticamente equivalente a la estrategia de Vista Servlet, es una solución más elegante y más utilizada. Las vistas son el dominio de los diseñadores Web, que prefieren un lenguaje de marcas al código Java. El siguiente ejemplo muestra un ejemplo de código para esta estrategia. El fragmento es de un fichero fuente llamado welcome.jsp, al que nos reenvia un controlador servlet después de situar el JavaBean WelcomeHelper en el ámbito de la peticion:


<jsp:useBean id="welcomeHelper" scope="request"
  class="corepatterns.util.WelcomeHelper" />

<HTML>
<BODY bgcolor="FFFFFF">
<% if (welcomeHelper.nameExists())
{ 
%>
<center><H3> Welcome <destacar>
<jsp:getProperty name="welcomeHelper" property="name" />
</destacar><br><br> </H3></center>
<%
}
%>
  
<H4><center>Glad you are visiting our 
  site!</center></H4>

</BODY>
</HTML>

La estrategia alternativa de Vista Servlet normalmente se implementa embebiendo marcas HTML directamente dentro del código Java. Mezclar código Java y etiquetas de marcas crea una pobre separación de los roles de usuario dentro de un proyecto e incrementa las dependencias de los mismos recursos entre varios miembros de diferentes equipos. Cuando un individuo trabaja en una plantilla que contiene código o etiquetas no familiares, incrementa el riesgo de que un cambio accidental introduzca problemas en el sistema. También hay una reducción de la eficiencia del entorno de trabajo (demasiada gente compartiendo los mismos recursos físicos) y un incremento en el manejo de control de fuentes.

Estos problemas ocurren más frecuentemente en grandes entornos empresariales que tienen requerimientos de sistemas más complicados y que utilizan equipos de desarrolladores. Tiene menos probabilidades de ocurrir en pequeños sistemas que tienen sencillos requerimientos y utilizan unos pocos desarrolladores porque el mismo individuo cumple los roles mencionados arriba. Sin embargo, debemos tener en mente que los proyectos suelen empezar pequeños -- con requerimiento sencillos y unos cuantos desarrolladores -- pero finalmente evolucionan y se convierten en suficientemente sofisticados como para beneficiarse de estas sugerencias.

. Servlet View

La estrategia de Vista Servlet utiliza un servlet como la vista. Es semánticametne equivalente al estrategia preferida de Vista JSP. Sin embargo, la estrategia de Vista Servlet, como vemos en el ejemplo siguiente, es más engorrosa para los equipos de desarrollo de software y de producción Web porque embebe etiquetas de marcas dentro del código Java. Cuando las etiquetas se mezclan con el código Jaba, la plantilla de la vista es más difícil de actualizar y modificar.


public class Controller extends HttpServlet {
  public void init(ServletConfig config) throws 
    ServletException {
    super.init(config);
  }

  public void destroy() { }

  /** Processes requests for both HTTP  
   * <code>GET</code> and <code>POST</code> methods.
   * @param request servlet request
   * @param response servlet response
   */
  protected void processRequest(HttpServletRequest 
    request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
    String title = "Servlet View Strategy";
    try {
      response.setContentType("text/html");
      java.io.PrintWriter out = response.getWriter();
      out.println("<html><title>"+title+"</title>");
      out.println("<body>");
      out.println("<h2><center>Employees List</h2>");
      EmployeeDelegate delegate = 
          new EmployeeDelegate();

      /** ApplicationResources provides a simple API 
        * for retrieving constants and other    
        * preconfigured values**/
      Iterator employees = delegate.getEmployees( 
            ApplicationResources.getInstance().
                getAllDepartments());
      out.println("<table border=2>");
      out.println("<tr><th>First Name</th>" + 
        "<th>Last Name</th>" + 
          "<th>Designation</th><th>Id</th></tr>");
      while (employees.hasNext())                       {
        out.println("<tr>");
        EmployeeTO emp = (EmployeeTO)employees.next();
        out.println("<td>"+emp.getFirstName()+
            "</td>");
        out.println("<td>"+emp.getLastName()+ 
            "</td>");
        out.println("<td>"+emp.getDesignation()+
            "</td>");
        out.println("<td>"+emp.getId()+"</td>");
        out.println("</tr>");
}
      out.println("</table>");
      out.println("<br><br>");
      out.println("</body>");
      out.println("</html>");
      out.close();
    }
    catch (Exception e) {
      LogManager.logMessage("Handle this exception",
        e.getMessage() );
    }
  }

  /** Handles the HTTP <code>GET</code> method.
    * @param request servlet request
    * @param response servlet response
    */
  protected void doGet(HttpServletRequest request, 
    HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
  }

  /** Handles the HTTP <code>POST</code> method.
    * @param request servlet request
    * @param response servlet response
    */
  protected void doPost(HttpServletRequest request, 
    HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
  }

  /** Returns a short description of the servlet. */
  public String getServletInfo() {
    return "Example of Servlet View. " + 
              "JSP View is preferable.";
  }

  /** dispatcher method **/
  protected void dispatch(HttpServletRequest request, 
      HttpServletResponse response, String page) 
  throws javax.servlet.ServletException,
      java.io.IOException       {
    RequestDispatcher dispatcher = 
      getServletContext().getRequestDispatcher(page);
    dispatcher.forward(request, response);
  }
}

. JavaBean Helper

El helper se implementa como un JavaBean. La utilización de helpers resulta en una separación limpia de la vista y el procesamiento de negocio en una aplicación, ya que la lógica de negocio está construida fuera de la vista y dentro del componente helper. En este caso, la lógica de negocio se encapsula en un JavaBean, que ayuda en la recuperación de contenido y adapta y almacena el modelo para usarlo en la vista.

La utilización de la estrategia JavaBean Helper requiere menos trabajo que la estrategia Custom Tag Helper, ya que los JavaBeans se construyen e integran más facilmente en un entorno JSP. Además, incluso los desarrolaldores novatos entienden los JavaBeans. En el siguiente código podemos ver un ejemplo de esta estrategia:


<jsp:useBean id="welcomeHelper" scope="request"
  class="corepatterns.util.WelcomeHelper" />

<HTML>
<BODY bgcolor="FFFFFF">
<% if (welcomeHelper.nameExists())
{ 
%>
<center><H3> Welcome <destacar>
<jsp:getProperty name="welcomeHelper" property="name" />
</destacar><br><br> </H3></center>
<%
} 
%>
  
<H4><center>Glad you are visiting our 
  site!</center></H4>

</BODY>
</HTML>

. Custom Tag Helper

El helper se implementa como una etiqueta personalizada (sólo JSP 1.1+). La utilización de helpers resulta en una separación limpia de la vista y el procesamiento de negocio en una aplicación, ya que la lógica de negocio está construida fuera de la vista y dentro del componente helper. En este caso, la lógica de negocio se encapsula en un componente de etiqueta personalizada, que podría ayudar en la recuperación de contenido y adaptar el modelo para su utilización en la vista.

Usar esta estrategia requier mucho más trabajo que hacerlo con la estrategia JavaBean Helper, ya que el desarrollo de etiquetas personalizadas es moderadamente complicado en relación al desarrollo de JavaBeans. No solo es más complejo el proceso de desarrollo, sino que hay mucha complejidad con respecto a la integración y el manejo de las etiquetas completadas. Para utilizar esta estrategia, debemos configurar el entorno con numerosos artefactos generados, incluyendo la propia etiqueta, un descriptor de librería de etiquetas, y los ficheros de configuración. Abajo podemos ver un fragmento de una vista JSP que utiliza esta estrategia:


<%@ taglib uri="/web-INF/corepatternstaglibrary.tld"
  prefix="corepatterns" %>
<html>
<head><title>Employee List</title></head>
<body>

<div align="center">
<h3> List of employees in <corepatterns:department 
  attribute="id"/> department - Using Custom Tag 
  Helper Strategy. </h3>
<table border="1" >
    <tr>
        <th> First Name </th>
        <th> Last Name </th>
        <th> Designation </th>
        <th> Employee Id </th>
        <th> Tax Deductibles </th>
        <th> Performance Remarks </th>
        <th> Yearly Salary</th>
    </tr>
    <corepatterns:employeelist id="employeelist_key">
    <tr>
        <td><corepatterns:employee 
            attribute="FirstName"/> </td>
        <td><corepatterns:employee 
            attribute= "LastName"/></td> 
        <td><corepatterns:employee 
            attribute= "Designation"/> </td>
        <td><corepatterns:employee 
            attribute= "Id"/></td> 
        <td><corepatterns:employee 
            attribute="NoOfDeductibles"/></td>
        <td><corepatterns:employee 
            attribute="PerformanceRemarks"/></td>
        <td><corepatterns:employee 
            attribute="YearlySalary"/></td>
        <td>
     </tr>
    </corepatterns:employeelist>
</table>
</div>
</body>
</html>

. Business Delegate as Helper

Los componentes helper normalmente hacen llamadas distribuidas a la capa de negocio. Sugerimos la utilización de un delegado de negocio para poder ocultar los detalles de la implementación subyacente, así como dicho helper simplemente invoca un servicio de negocio sin conocer los detalles sobre su implementación física y su distribución.

Tanto el helper como el delegado de negocio deben implementarse como JavaBeans. Así, se podría combinar la noción del componente helper y del delegado de negocio e implementar el delegado de negocio como un tipo de helper especializado. Hay una mayor distinción entre un helper y un delegado de negocio: Un desarrollador que trabaja en la capa de presentación escribe un componente helper, mientras que el delegado normalmente lo escribe un desarrollador que trabaja en los servicios de la capa de negocio. (Nota: El delegado también se podría proporcionar como una parte del marco de trabajo). Así, está estrategia trato mucho más sobre quién escribe realmente el delegado que sobre la propia implementación. Si hay algún solapamiento en los roles de desarrollo, entonces deberiamos considerar la utilización de esta estrategia.


/**A servlet delegates to a command object helper, as
  shown in the following excerpt:**/
String resultPage = command.execute(request,
  response);

/**The command object helper uses the business
  delegate, which is simply implemented as another
  JavaBean helper, as shown in the following excerpt:**/

  AccountDelegate accountDelegate = new 
  AccountDelegate();

Una nota sobre los Helpers:

Los helpers JavaBean se utilizan para ayudar en la recuperación de contenido y en el almacenamiento y adaptación del modelo para la vista. Los helpers JavaBean también se utilizan frecuentemente como objetos Command.

Al igual que los helpers JavaBean, los helpers de etiquetas personalizadas podrían cumplir cualquiera de estos roles, excepto el de actuar como un objeto command. Al contrario que los helpers JavaBean, los helpers de etiquetas personalizadas están bien diseñados para el control de flujo y la interacción con la vista. Los helpers de etiquetas personalizadas utilizados de esta forma encapsulan lógica que de otro modo podría embeberse directamente dentro de la página JSP como código scriptlet. Otra área donde es preferible utilizar helpers de etiquetas personalizadas es en el formato de datos para display. Una etiqueta personalizada puede iterar sobre una colección de resultados, formatear esos resultados en un tabla HTML, y embeber la tabla dentro de la vista JSP sin requerir ningún scriptlet Java.

Consideremos un ejemplo en el que le pedimos a un cliente Web alguna información de la cuenta del sistema, como se ve en la siguiente figura.

Podemos ver cinco helpers en este diagrama. Los cuatro helpers JavaBean son el objeto AccountCommand, el objeto Account, el objeto AccountDAO, y AccountDetails. El único helper de etiqueta personalizada es el objeto TableFormatter.

El controlador maneja la petición. Crea o busca el objeto command apropiado, que está implementado como un helper JavaBean. En este caso, es el objeto command que procesa las peticiones de información de la cuenta. El controlador invoca al objeto Command, que le pide la información sobre la cuenta a un objeto Account. El objeto Account invoca al servicio de negocio, pidíendole estos detalles, que se devuelven en forma de un objeto Transfer implementado como un JavaBean.

¿Entonces, como accede el objeto Account a los servicios de negocio? Examinemos dos casos, uno sencillo y otro un poco más complicado. En el caso sencillo, imaginemos que un proyecto está en fase de aproximación, enfasando Enterprise JavaBeans (EJB) dentro de la capa de negocio en el tiempo. Asumamos que estámos en el momento en que se está accediendo a la base de datos mediante llamadas JDBC desde la capa de presentación. En ese caso, el objeto Account utiliza un objeto Data Access (en páginas posteriores veremos este patrón), ocultando los detalles de implementación para acceder a la base de datos. El objeto Data Access sabe qué consultas SQL son las necesarias para recuperar la información. Estos detalles están ocultos del resto de la aplicación, reduciendo el acoplamiento y haciendo que todos los componentes sean más modulares y reutilizables. Este es el caso descrito en el diagrama de secuencia anterior.

Cuando la arquitectura se vuelve más sofisticada, se introduce un EJB en la capa de negocio, entonces el objeto Data Access se reemplaza con un Business Delegate (más adelante veremos este patrón), que normalmente está escrito por los desarrolladores de servicios de negocio. El delegado oculta los detalles de implementación de la búsqueda EJB, de la invocación y del manejo de excepciones. También podría mejorar el rendimiento proporcionando servicio de caché. De nuevo, el objeto reduce el acoplamiento entre las capas, mejorando la reutilización y la modularidad de varios componentes. Sin importar la implementación específica de este objeto, su interface podría permanecer invariable durante esta transición. La siguiente figura describe este escenario después de la transición al delegado de negocio.

Ahora el objeto command tiene que manejar el objeto AccountDetails, el cual almacena antes de devolver el control al controlador. El Controller lo reenvia a la vista apropiada, llamada AccountView.jsp. Entonces la vista obtiene una combinación de datos en bruto y de datos formateados de los helpers AccountDetails y TableFormatter, respectivamente. TableFormatter está implementado como una etiqueta personalizada que pasa a través de los datos en bruto y los formatea en una tabla HTML para mostrarla. Como vimos, esta conversión no requiere escribir nigún scriptlet en la vista, lo que sí sería necesario para realizar la misma funcionalidad con un helper JavaBean.

Además, el objeto Account o el helper AccountDetails podrían proporcionar métodos convenientes para adaptar los datos en bruto a otros formatos. Aunque dichos métodos no introducirían etiquetas HTML en los datos, podrían proporcionar diferentes combinaciones de datos. Un ejemplo es entregar el nombre completo del usuario en varios formatos, como "Lastname, Firstname" o "Firstname Lastname", etc.

. Transformer Helper

El helper se implementa como un eXtensible Stylesheet Language Transformer. Esto es particularmente útil con modelos que existen como marcas estructuradas, como el lenguaje eXtensible Markup Language (XML), bien nativamente dentro de sistemas legales o mediante alguna forma de conversión. Utilizar esta estrategia puede ayudarnos a forzar la separación entre el modelo y la vista, ya que la mayoría de las marcas de la vista se tienen que crear en una hoja de estilos separada. La siguiente figura describe una potencial implementación de esta estrategia:

El controlador maneja la petición e invoca al objeto Command, implementado como un helper JavaBean. El objeto Command inicia la recuperación de los datos de la cuenta. El objeto Account invoca al servicio de negocio, que devuelve los datos en forma de un objeto Transfer, implementado como un JavaBean.

Se completa la recuperación de contenido y el control se pasa al AccountView, que utiliza su etiqueta personalizada transformer para manipular el estado del modelo. El transformer trata con un hoja de estilo, que describe cómo transformar el modelo, normalmente describiendo cómo formatearlo con etiquetas para mostrarlo en el cliente. La hoja de estilo normalmente se recupera como un fichero estático, aunque se podría generar dinámicamente. Aquí tenemos un ejemplo de lo que debería ser la etiqueta personalizada:


<xsl:transform model="accounthelper"
 stylesheet="/transform/styles/basicaccount.xsl"/>

. Consecuencias

  • Mejora el Particionamiento de la Aplicación, la Reutilización y el Mantenimiento
    Utilizar helpers resulta en una clara separación de la vista del procesamiento de negocio en una aplicación. Los helpers, en forma de JavaBeans (JSP 1.0+) y etiquetas personalizadas (JSP 1.1+), proporcionan un lugar externo para que la vista encapsule la lógica de negocio. Por el contrario, el código en scriptlets dentro de las páginas JSP, emborrona ampliamente la situación, especialmente en gandes proyectos.

    Además, la lógica de negocio que se construye fuera de las JSPs y dentro de los JavaBeans y las etiquetas personalizadas se reutiliza, reduciendo la duplicación y facilitando el mantenimiento.

  • Mejora la Separación de Roles
    Separar la lógica del formateo de la lógica de negocio de la aplicación reduce las dependencias podrían tener los individuos que juegan los diferentes roles en los mismos recursos. Por ejemplo, un desarrollador de software podría poseer código que está embebido dentro de marcas HTML, mientras que un miembro del equipo de producción Web podría necesitar modificar la distribución de la página y diseñar componentes que están mezclados con la lógia de negocios. Ningún individuo que cumpla estos roles podría estar familiarizado con las implementaciones específicas del trabajo del otro individuo, y asi se evita el riesgo de introducir bugs mediante modificaciones accidentales del sistema.

. Patrones Relacionados

  • Business Delegate
    Los componentes helper necesitan métodos de acceso al API de servicios de negocio. También es importante reducir el acoplamiento entre helpers en la capa de presentación y entre servicios de negocio en la capa de negocio. Se recomienda que se utilice un delegate porque estas capas podrían estar distribuidas físicamente por la red. El delegado le oculta al clinte los detalles subyacentes de la búsqueda y acceso a los servicios de negocio, y también podría proporcionar un caché intermedio para reducir el tráfico de la red.
  • Dispatcher View y Service to Worker
    Cuando sea deseable el control centralizado para manejar problemas como la seguridad, el control del carga de trabajo, la recuperación de contenidos y la navegación, debemos considerar la utilización de los patrones Dispatcher View o Service to Worker.
  • Front Controller
    Este patrón está emparejado con el patrón View Helper para crear los patrones Dispatcher View o Service to Worker.
 
Patrocinados
 

Copyright © 1999-2006 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad

Hospedaje web y servidores dedicados linux por Ferca Network