Files
java-design-patterns/localization/es/composite-view

title, shortTitle, category, language, tag
title shortTitle category language tag
Composite View Composite View Structural es
Enterprise patterns
Presentation

Propósito

El objetivo principal del patrón de diseño Composite View es componer objetos en estructuras de árbol para representar jerarquías parte-todo. Esto permite a los clientes tratar objetos individuales y composiciones de objetos de manera uniforme, simplificando la gestión de estructuras complejas.

Explicación

Ejemplo del mundo real

Un sitio de noticias quiere mostrar la fecha actual y las noticias a diferentes usuarios basándose en las preferencias de ese usuario. El sitio de noticias sustituirá en diferentes componentes de alimentación de noticias en función de los intereses del usuario, por defecto a las noticias locales.

En pocas palabras

El patrón de vista compuesta consiste en tener una vista principal compuesta por subvistas más pequeñas. El diseño de esta vista compuesta se basa en una plantilla. Un View-manager decide entonces qué subvistas incluir en esta plantilla.

Wikipedia dice

Vistas compuestas que están formadas por múltiples subvistas atómicas. Cada componente de la plantilla puede incluirse dinámicamente en el conjunto y el diseño de la página puede gestionarse independientemente del contenido. Esta solución permite crear una vista compuesta basada en la inclusión y sustitución de fragmentos modulares de plantillas dinámicas y estáticas. Promueve la reutilización de porciones atómicas de la vista fomentando el diseño modular.

Ejemplo programático

Dado que se trata de un patrón de desarrollo web, se requiere un servidor para demostrarlo. Este ejemplo utiliza Tomcat 10.0.13 para ejecutar el servlet, y este ejemplo programático sólo funcionará con Tomcat 10+.

En primer lugar, existe AppServlet que es un HttpServlet que se ejecuta en Tomcat 10+.

public class AppServlet extends HttpServlet {
    private String msgPartOne = "<h1>This Server Doesn't Support";
    private String msgPartTwo = "Requests</h1>\n"
            + "<h2>Use a GET request with boolean values for the following parameters<h2>\n"
            + "<h3>'name'</h3>\n<h3>'bus'</h3>\n<h3>'sports'</h3>\n<h3>'sci'</h3>\n<h3>'world'</h3>";

    private String destination = "newsDisplay.jsp";

    public AppServlet() {

    }

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        RequestDispatcher requestDispatcher = req.getRequestDispatcher(destination);
        ClientPropertiesBean reqParams = new ClientPropertiesBean(req);
        req.setAttribute("properties", reqParams);
        requestDispatcher.forward(req, resp);
    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println(msgPartOne + " Post " + msgPartTwo);

    }

    @Override
    public void doDelete(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println(msgPartOne + " Delete " + msgPartTwo);

    }

    @Override
    public void doPut(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println(msgPartOne + " Put " + msgPartTwo);

    }
}

Este servlet no forma parte del patrón, y simplemente reenvía las peticiones GET a la JSP correcta. Las peticiones PUT, POST y DELETE no están soportadas y simplemente mostrarán un mensaje de error.

La gestión de la vista en este ejemplo se realiza a través de una clase javabean: ClientPropertiesBean, que almacena las preferencias del usuario.

public class ClientPropertiesBean implements Serializable {

    private static final String WORLD_PARAM = "world";
    private static final String SCIENCE_PARAM = "sci";
    private static final String SPORTS_PARAM = "sport";
    private static final String BUSINESS_PARAM = "bus";
    private static final String NAME_PARAM = "name";

    private static final String DEFAULT_NAME = "DEFAULT_NAME";
    private boolean worldNewsInterest;
    private boolean sportsInterest;
    private boolean businessInterest;
    private boolean scienceNewsInterest;
    private String name;

    public ClientPropertiesBean() {
        worldNewsInterest = true;
        sportsInterest = true;
        businessInterest = true;
        scienceNewsInterest = true;
        name = DEFAULT_NAME;

    }

    public ClientPropertiesBean(HttpServletRequest req) {
        worldNewsInterest = Boolean.parseBoolean(req.getParameter(WORLD_PARAM));
        sportsInterest = Boolean.parseBoolean(req.getParameter(SPORTS_PARAM));
        businessInterest = Boolean.parseBoolean(req.getParameter(BUSINESS_PARAM));
        scienceNewsInterest = Boolean.parseBoolean(req.getParameter(SCIENCE_PARAM));
        String tempName = req.getParameter(NAME_PARAM);
        if (tempName == null || tempName == "") {
            tempName = DEFAULT_NAME;
        }
        name = tempName;
    }
    // getters and setters generated by Lombok 
}

Este javabean tiene un constructor por defecto, y otro que toma un HttpServletRequest.

Este segundo constructor toma el objeto de solicitud, analiza los parámetros de la solicitud que contienen las preferencias del usuario para los diferentes tipos de noticias.

La plantilla para la página de noticias está en newsDisplay.jsp.


<html>
<head>
    <style>
        h1 {
            text-align: center;
        }

        h2 {
            text-align: center;
        }

        h3 {
            text-align: center;
        }

        .centerTable {
            margin-left: auto;
            margin-right: auto;
        }

        table {
            border: 1px solid black;
        }

        tr {
            text-align: center;
        }

        td {
            text-align: center;
        }
    </style>
</head>
<body>
<%ClientPropertiesBean propertiesBean = (ClientPropertiesBean) request.getAttribute("properties");%>
<h1>Welcome <%= propertiesBean.getName()%></h1>
<jsp:include page="header.jsp"></jsp:include>
<table class="centerTable">

    <tr>
        <td></td>
        <% if(propertiesBean.isWorldNewsInterest()) { %>
        <td><%@include file="worldNews.jsp"%></td>
        <% } else { %>
        <td><%@include file="localNews.jsp"%></td>
        <% } %>
        <td></td>
    </tr>
    <tr>
        <% if(propertiesBean.isBusinessInterest()) { %>
        <td><%@include file="businessNews.jsp"%></td>
        <% } else { %>
        <td><%@include file="localNews.jsp"%></td>
        <% } %>
        <td></td>
        <% if(propertiesBean.isSportsInterest()) { %>
        <td><%@include file="sportsNews.jsp"%></td>
        <% } else { %>
        <td><%@include file="localNews.jsp"%></td>
        <% } %>
    </tr>
    <tr>
        <td></td>
        <% if(propertiesBean.isScienceNewsInterest()) { %>
        <td><%@include file="scienceNews.jsp"%></td>
        <% } else { %>
        <td><%@include file="localNews.jsp"%></td>
        <% } %>
        <td></td>
    </tr>
</table>
</body>
</html>

Esta página JSP es la plantilla. Declara una tabla con tres filas, con un componente en la primera fila, dos componentes en la segunda fila y un componente en la tercera fila.

Los scriplets en el archivo son parte de la estrategia de gestión de vistas que incluyen diferentes subvistas atómicas basadas en las preferencias del usuario en el Javabean.

A continuación se muestran dos ejemplos de las subvistas atómicas simuladas utilizadas en el compuesto: businessNews.jsp


<html>
<head>
    <style>
        h2 {
            text-align: center;
        }

        table {
            border: 1px solid black;
        }

        tr {
            text-align: center;
        }

        td {
            text-align: center;
        }
    </style>
</head>
<body>
<h2>
    Generic Business News
</h2>
<table style="margin-right: auto; margin-left: auto">
    <tr>
        <td>Stock prices up across the world</td>
        <td>New tech companies to invest in</td>
    </tr>
    <tr>
        <td>Industry leaders unveil new project</td>
        <td>Price fluctuations and what they mean</td>
    </tr>
</table>
</body>
</html>

localNews.jsp


<html>
<body>
<div style="text-align: center">
    <h3>
        Generic Local News
    </h3>
    <ul style="list-style-type: none">
        <li>
            Mayoral elections coming up in 2 weeks
        </li>
        <li>
            New parking meter rates downtown coming tomorrow
        </li>
        <li>
            Park renovations to finish by the next year
        </li>
        <li>
            Annual marathon sign ups available online
        </li>
    </ul>
</div>
</body>
</html>

Los resultados son los siguientes:

  1. El usuario ha puesto su nombre como Tammy en los parámetros de la petición y ninguna preferencia: alt text
  2. El usuario ha puesto su nombre como Johnny en los parámetros de la petición y tiene preferencia por noticias del mundo, negocios y ciencia: alt text

Las distintas subvistas como worldNews.jsp, businessNews.jsp, etc. se incluyen condicionalmente en función de los parámetros de la solicitud.

Cómo utilizarlo

Para probar este ejemplo, asegúrese de tener Tomcat 10+ instalado. Configure su IDE para construir un archivo WAR a partir del módulo y despliegue ese archivo en el servidor

IntelliJ:

En Run y edit configurations Asegúrate de que el servidor Tomcat es una de las configuraciones de ejecución. Vaya a la pestaña de despliegue y asegúrese de que se está construyendo un artefacto llamado composite-view:war exploded. Si no está presente, añada uno.

Asegúrate de que el artefacto se está construyendo a partir del contenido del directorio web y de los resultados de la compilación del módulo. Apunta la salida del artefacto a un lugar conveniente. Ejecute la configuración y vea la página de destino, siga las instrucciones de esa página para continuar.

Diagrama de clases

alt text

El diagrama de clases aquí muestra el Javabean que es el gestor de vistas. Las vistas son JSP's dentro del directorio web.

Aplicabilidad:

Utiliza el patrón de diseño Composite View cuando:

Desea representar jerarquías parciales de objetos.

  • Esperas que las estructuras compuestas puedan incluir nuevos componentes en el futuro.
  • Desea que los clientes puedan ignorar la diferencia entre composiciones de objetos y objetos individuales. Los clientes tratarán todos los objetos de la estructura compuesta de manera uniforme.

Usos conocidos

  • Interfaces gráficas de usuario (GUI) en las que los widgets pueden contener otros widgets (por ejemplo, una ventana con paneles, botones y campos de texto).
  • Estructuras de documentos, como la representación de tablas que contienen filas, que a su vez contienen celdas, todas las cuales pueden tratarse como elementos de una jerarquía unificada.

Consecuencias

Ventajas:

  • Gran flexibilidad a la hora de añadir nuevos componentes: Como los compuestos y los nodos hoja se tratan de manera uniforme, es más fácil añadir nuevos tipos de componentes.
  • Código cliente simplificado: Los clientes pueden tratar las estructuras compuestas y los elementos individuales de manera uniforme, lo que reduce la complejidad del código cliente.

Contrapartidas:

  • Generalización excesiva: El diseño del sistema puede volverse más complejo si haces que todo sea compuesto, especialmente si tu aplicación no lo requiere.
  • Dificultad en la aplicación de restricciones: Puede ser más difícil restringir los componentes de un compuesto a sólo ciertos tipos.

Patrones Relacionados

  • Decorator: Mientras que Decorator se utiliza para añadir responsabilidades a los objetos, Composite está pensado para construir estructuras de objetos.
  • Flyweight: Composite puede combinarse a menudo con Flyweight para implementar nodos hoja compartidos en una estructura compuesta, reduciendo la huella de memoria.
  • Cadena de responsabilidad: Puede usarse con Composite para permitir a los componentes pasar peticiones a través de la jerarquía.
  • Composite
  • Ayudante de vista

Créditos