Browser docs

Composite View

Name

Composite View

Intent

The purpose of the Composite View Pattern is to increase re-usability and flexibility when creating views for websites/webapps. This pattern seeks to decouple the content of the page from its layout, allowing changes to be made to either the content or layout of the page without impacting the other. This pattern also allows content to be easily reused across different views easily.

Explanation

Real World Example

A news site wants to display the current date and news to different users based on that user’s preferences. The news site will substitute in different news feed components depending on the user’s interest, defaulting to local news.

In Plain Words

Composite View Pattern is having a main view being composed of smaller subviews. The layout of this composite view is based on a template. A View-manager then decides which subviews to include in this template.

Wikipedia Says

Composite views that are composed of multiple atomic subviews. Each component of the template may be included dynamically into the whole and the layout of the page may be managed independently of the content. This solution provides for the creation of a composite view based on the inclusion and substitution of modular dynamic and static template fragments. It promotes the reuse of atomic portions of the view by encouraging modular design.

Programmatic Example

Since this is a web development pattern, a server is required to demonstrate it. This example uses Tomcat 10.0.13 to run the servlet, and this programmatic example will only work with Tomcat 10+.

Firstly there is AppServlet which is an HttpServlet that runs on Tomcat 10+.

 1public class AppServlet extends HttpServlet {
 2  private String msgPartOne = "<h1>This Server Doesn't Support";
 3  private String msgPartTwo = "Requests</h1>\n"
 4      + "<h2>Use a GET request with boolean values for the following parameters<h2>\n"
 5      + "<h3>'name'</h3>\n<h3>'bus'</h3>\n<h3>'sports'</h3>\n<h3>'sci'</h3>\n<h3>'world'</h3>";
 6
 7  private String destination = "newsDisplay.jsp";
 8
 9  public AppServlet() {
10
11  }
12
13  @Override
14  public void doGet(HttpServletRequest req, HttpServletResponse resp)
15          throws ServletException, IOException {
16    RequestDispatcher requestDispatcher = req.getRequestDispatcher(destination);
17    ClientPropertiesBean reqParams = new ClientPropertiesBean(req);
18    req.setAttribute("properties", reqParams);
19    requestDispatcher.forward(req, resp);
20  }
21
22  @Override
23  public void doPost(HttpServletRequest req, HttpServletResponse resp)
24          throws ServletException, IOException {
25    resp.setContentType("text/html");
26    PrintWriter out = resp.getWriter();
27    out.println(msgPartOne + " Post " + msgPartTwo);
28
29  }
30
31  @Override
32  public void doDelete(HttpServletRequest req, HttpServletResponse resp)
33          throws ServletException, IOException {
34    resp.setContentType("text/html");
35    PrintWriter out = resp.getWriter();
36    out.println(msgPartOne + " Delete " + msgPartTwo);
37
38  }
39
40  @Override
41  public void doPut(HttpServletRequest req, HttpServletResponse resp)
42          throws ServletException, IOException {
43    resp.setContentType("text/html");
44    PrintWriter out = resp.getWriter();
45    out.println(msgPartOne + " Put " + msgPartTwo);
46
47  }
48}

This servlet is not part of the pattern, and simply forwards GET requests to the correct JSP. PUT, POST, and DELETE requests are not supported and will simply show an error message.

The view management in this example is done via a javabean class: ClientPropertiesBean, which stores user preferences.

 1public class ClientPropertiesBean implements Serializable {
 2
 3  private static final String WORLD_PARAM = "world";
 4  private static final String SCIENCE_PARAM = "sci";
 5  private static final String SPORTS_PARAM = "sport";
 6  private static final String BUSINESS_PARAM = "bus";
 7  private static final String NAME_PARAM = "name";
 8
 9  private static final String DEFAULT_NAME = "DEFAULT_NAME";
10  private boolean worldNewsInterest;
11  private boolean sportsInterest;
12  private boolean businessInterest;
13  private boolean scienceNewsInterest;
14  private String name;
15  
16  public ClientPropertiesBean() {
17    worldNewsInterest = true;
18    sportsInterest = true;
19    businessInterest = true;
20    scienceNewsInterest = true;
21    name = DEFAULT_NAME;
22
23  }
24  
25  public ClientPropertiesBean(HttpServletRequest req) {
26    worldNewsInterest = Boolean.parseBoolean(req.getParameter(WORLD_PARAM));
27    sportsInterest = Boolean.parseBoolean(req.getParameter(SPORTS_PARAM));
28    businessInterest = Boolean.parseBoolean(req.getParameter(BUSINESS_PARAM));
29    scienceNewsInterest = Boolean.parseBoolean(req.getParameter(SCIENCE_PARAM));
30    String tempName = req.getParameter(NAME_PARAM);
31    if (tempName == null || tempName == "") {
32      tempName = DEFAULT_NAME;
33    }
34    name = tempName;
35  }
36  // getters and setters generated by Lombok 
37}

This javabean has a default constructor, and another that takes an HttpServletRequest. This second constructor takes the request object, parses out the request parameters which contain the user preferences for different types of news.

The template for the news page is in newsDisplay.jsp

 1<html>
 2<head>
 3    <style>
 4        h1 { text-align: center;}
 5        h2 { text-align: center;}
 6        h3 { text-align: center;}
 7        .centerTable {
 8            margin-left: auto;
 9            margin-right: auto;
10        }
11        table {border: 1px solid black;}
12        tr {text-align: center;}
13        td {text-align: center;}
14    </style>
15</head>
16<body>
17    <%ClientPropertiesBean propertiesBean = (ClientPropertiesBean) request.getAttribute("properties");%>
18    <h1>Welcome <%= propertiesBean.getName()%></h1>
19    <jsp:include page="header.jsp"></jsp:include>
20    <table class="centerTable">
21
22        <tr>
23            <td></td>
24            <% if(propertiesBean.isWorldNewsInterest()) { %>
25                <td><%@include file="worldNews.jsp"%></td>
26            <% } else { %>
27                <td><%@include file="localNews.jsp"%></td>
28            <% } %>
29            <td></td>
30        </tr>
31        <tr>
32            <% if(propertiesBean.isBusinessInterest()) { %>
33                <td><%@include file="businessNews.jsp"%></td>
34            <% } else { %>
35                <td><%@include file="localNews.jsp"%></td>
36            <% } %>
37            <td></td>
38            <% if(propertiesBean.isSportsInterest()) { %>
39                <td><%@include file="sportsNews.jsp"%></td>
40            <% } else { %>
41                <td><%@include file="localNews.jsp"%></td>
42            <% } %>
43        </tr>
44        <tr>
45            <td></td>
46            <% if(propertiesBean.isScienceNewsInterest()) { %>
47                <td><%@include file="scienceNews.jsp"%></td>
48            <% } else { %>
49                <td><%@include file="localNews.jsp"%></td>
50            <% } %>
51            <td></td>
52        </tr>
53    </table>
54</body>
55</html>

This JSP page is the template. It declares a table with three rows, with one component in the first row, two components in the second row, and one component in the third row.

The scriplets in the file are part of the view management strategy that include different atomic subviews based on the user preferences in the Javabean.

Here are two examples of the mock atomic subviews used in the composite: businessNews.jsp

 1<html>
 2    <head>
 3        <style>
 4            h2 { text-align: center;}
 5            table {border: 1px solid black;}
 6            tr {text-align: center;}
 7            td {text-align: center;}
 8        </style>
 9    </head>
10    <body>
11        <h2>
12            Generic Business News
13        </h2>
14        <table style="margin-right: auto; margin-left: auto">
15            <tr>
16                <td>Stock prices up across the world</td>
17                <td>New tech companies to invest in</td>
18            </tr>
19            <tr>
20                <td>Industry leaders unveil new project</td>
21                <td>Price fluctuations and what they mean</td>
22            </tr>
23        </table>
24    </body>
25</html>

localNews.jsp

 1<html>
 2    <body>
 3        <div style="text-align: center">
 4            <h3>
 5                Generic Local News
 6            </h3>
 7            <ul style="list-style-type: none">
 8                <li>
 9                    Mayoral elections coming up in 2 weeks
10                </li>
11                <li>
12                    New parking meter rates downtown coming tomorrow
13                </li>
14                <li>
15                    Park renovations to finish by the next year
16                </li>
17                <li>
18                    Annual marathon sign ups available online
19                </li>
20            </ul>
21        </div>
22    </body>
23</html>

The results are as such:

  1. The user has put their name as Tammy in the request parameters and no preferences: alt text
  2. The user has put their name as Johnny in the request parameters and has a preference for world, business, and science news: alt text

The different subviews such as worldNews.jsp, businessNews.jsp, etc. are included conditionally based on the request parameters.

How To Use

To try this example, make sure you have Tomcat 10+ installed. Set up your IDE to build a WAR file from the module and deploy that file to the server

IntelliJ:

Under Run and edit configurations Make sure Tomcat server is one of the run configurations. Go to the deployment tab, and make sure there is one artifact being built called composite-view:war exploded. If not present, add one.

Ensure that the artifact is being built from the content of the web directory and the compilation results of the module. Point the output of the artifact to a convenient place. Run the configuration and view the landing page, follow instructions on that page to continue.

Class diagram

alt text

The class diagram here displays the Javabean which is the view manager. The views are JSP’s held inside the web directory.

Applicability

This pattern is applicable to most websites that require content to be displayed dynamically/conditionally. If there are components that need to be re-used for multiple views, or if the project requires reusing a template, or if it needs to include content depending on certain conditions, then this pattern is a good choice.

Known uses

Most modern websites use composite views in some shape or form, as they have templates for views and small atomic components that are included in the page dynamically. Most modern Javascript libraries, like React, support this design pattern with components.

Consequences

Pros

  • Easy to re-use components
  • Change layout/content without affecting the other
  • Reduce code duplication
  • Code is more maintainable and modular

Cons

  • Overhead cost at runtime
  • Slower response compared to directly embedding elements
  • Increases potential for display errors

Credits