【Java设计模式】组合视图模式:增强应用程序中UI的一致性
一、概述
在Java中,组合视图设计模式有助于管理复杂的层次视图。本文将详细介绍该模式的意图、解释、编程示例、适用场景、实际应用、优点和权衡。同时,还将提供示例代码的下载链接,方便读者进行学习和实践。
二、组合视图设计模式的意图
组合视图设计模式的主要目标是将对象组合成树结构,以表示部分 - 整体层次结构。这允许客户端统一对待单个对象和对象的组合,简化了复杂层次视图的管理。
三、组合视图模式的详细解释及实际示例
- 实际示例:
- 组合视图设计模式的一个现实世界示例是Web应用程序中仪表板的布局。考虑一个金融仪表板,它显示各种小部件,如股票图表、最近的交易、账户余额和新闻提要。这些小部件中的每一个都是可以独立更新和管理的单独视图组件。通过使用组合视图模式,这些单独的小部件被组合成一个统一的仪表板视图。这种方法允许轻松地重新组织仪表板,添加新的小部件而不会干扰现有的小部件,并对整体布局进行一致的管理。这种视图的层次结构组合反映了仪表板的不同部分如何被视为单独的实体和更大整体的一部分。
- 通俗解释:
- 组合视图模式是指一个主视图由较小的子视图组成。这个组合视图的布局基于一个模板。然后,视图管理器决定在这个模板中包含哪些子视图。
- 维基百科解释:
- 组合视图由多个原子子视图组成。模板的每个组件都可以动态地包含在整体中,页面的布局可以独立于内容进行管理。该解决方案基于模块化动态和静态模板片段的包含和替换来创建组合视图。它通过鼓励模块化设计促进了视图原子部分的重用。
四、Java中组合视图模式的编程示例
一个新闻网站希望根据用户的偏好向不同用户显示当前日期和新闻。新闻网站将根据用户的兴趣替换不同的新闻提要组件,默认为本地新闻。
由于这是一个Web开发模式,需要一个服务器来演示它。这个示例使用Tomcat 10.0.13来运行Servlet,并且这个编程示例仅适用于Tomcat 10+。
首先,有一个AppServlet
,它是一个在Tomcat 10+上运行的HttpServlet
。
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);
}
}
这个Servlet不属于该模式的一部分,它只是将GET请求转发到正确的JSP。PUT、POST和DELETE请求不受支持,只会显示错误消息。
此示例中的视图管理通过一个JavaBean类:ClientPropertiesBean
完成,该类存储用户偏好。
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;
}
// Lombok生成的getter和setter
}
这个JavaBean有一个默认构造函数,还有一个接受HttpServletRequest
的构造函数。
这个第二个构造函数接受请求对象,解析出包含用户对不同类型新闻偏好的请求参数。
新闻页面的模板在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>
这个JSP页面是模板。它声明了一个包含三行的表格,第一行有一个组件,第二行有两个组件,第三行有一个组件。
文件中的脚本是视图管理策略的一部分,根据JavaBean中的用户偏好包含不同的原子子视图。
以下是组合中使用的模拟原子子视图的两个示例: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>
不同的子视图,如worldNews.jsp
、businessNews.jsp
等,根据请求参数有条件地包含。
如何使用
要尝试这个示例,请确保您安装了Tomcat 10+。设置您的IDE从模块构建WAR文件,并将该文件部署到服务器
IntelliJ:
在“运行”和“编辑配置”下,确保Tomcat服务器是运行配置之一。转到“部署”选项卡,并确保有一个名为“composite - view:war exploded”的工件正在构建。如果不存在,请添加一个。
确保该工件是根据“web”目录的内容和模块的编译结果构建的。将工件的输出指向一个方便的位置。运行配置并查看着陆页,按照该页面上的说明继续。
五、何时在Java中使用组合视图模式
当出现以下情况时使用组合视图设计模式:
- 您想要表示对象的部分 - 整体层次结构。
- 您预计组合结构将来可能会包含任何新组件。
- 您希望客户端能够忽略对象组合和单个对象之间的区别。客户端将统一对待组合结构中的所有对象。
六、组合视图模式在Java中的实际应用
- 图形用户界面(GUI),其中小部件可以包含其他小部件(例如,包含面板、按钮和文本字段的窗口)。
- 文档结构,例如包含行的表格的表示,行又包含单元格,所有这些都可以作为统一层次结构中的元素进行处理。
七、组合视图模式的优点和权衡
优点:
- 添加新组件的高度灵活性:由于组合和叶节点被统一对待,因此更容易添加新的组件类型。
- 简化客户端代码:客户端可以统一对待组合结构和单个元素,减少了客户端代码的复杂性。
权衡:
- 过度泛化:如果将所有内容都设计为组合,系统设计可能会变得更加复杂,特别是如果您的应用程序不需要这样做。
- 约束执行困难:将组合的组件限制为仅某些类型可能会更困难。
八、源码下载
https://download.csdn.net/download/weixin_42545951/89696137
通过本文的介绍,相信大家对Java中的组合视图模式有了更深入的了解。在实际开发中,合理运用该模式可以提高UI的一致性和可维护性,但需要注意避免过度泛化和约束执行的困难。