用 JavaServer Faces 2 实现可扩展 UI (3)
 
- UID
- 1066743
|

用 JavaServer Faces 2 实现可扩展 UI (3)
技巧 2:使用组合的方式在我的 CAD/CAM GUI 发布后不久,我花了几个月的时间与另一位开发人员 Bob 致力于一个新的项目。我们以 Bob 的代码为基础,而且不可思议地是,我们还能轻松进行更改并修复 bug。
我很快意识到 Bob 的代码和我的代码之间的最大区别是他编写了小 方法 — 通常是在代码的 5 至 15 行之间 — 并且他的整个系统都是由这些小方法拼接而成的。在我还在忙着修改我之前项目中具有很多关注点的长方法时,Bob 已经开始机敏地组合小方法和原子功能性了。Bob 的代码和我的代码在维护性和可扩展性方面自然也有着天壤之别,从那以后,我开始信服小方法。
虽然 Bob 和我那时都没有意识到,但是我们过去一直在使用 Smalltalk 的一种设计模式,称为 Composed Method(参见 ):
在一个抽象级别,将软件分成能执行单个任务的多个方法。 使用 Composed Method 模式的好处已经有大量书面记载(详细说明,请参见 Neal Ford 的 “” )。在这里,我将侧重于介绍如何在 JSF 视图中使用 Composed Method 模式。
JSF 2 鼓励使用较小的视图段组装视图。模板封装了常见功能,进而将视图分成了更小的块。JSF 2 还提供了一个 <ui:include> 标记,正如我在先前的代码清单中所展示的,这个标记可以让您将视图进一步分成更小的功能块。比如,图 2 展示了 places 应用程序的 login 页面的左菜单:
图 2. login 页面的左菜单 清单 5 显示了定义该菜单内容的文件:
清单 5. login 视图左菜单的实现1
2
3
4
5
6
7
8
9
10
11
12
13
| <ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<div class="menuLeftText">
#{msgs.welcomeGreeting}
<div class="welcomeImage">
<h:graphicImage library="images" name="cloudy.gif"/>
</div>
</div>
</html>
|
内的标记很简单,这就使文件更易于阅读、理解、维护和扩展。如果相同的代码埋藏在一个很长的、包含实现 login 视图所需的全部内容的 XHTML 页面内,那么它更改起来将会很繁琐。
图 3 显示了 places 视图的左菜单:
图 3. places 视图的左菜单 places 视图的左菜单的实现如清单 6 所示:
清单 6. places 视图的左菜单的实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| <ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:util="http://java.sun.com/jsf/composite/components/util">
<div class="placesSearchForm">
<div class="placesSearchFormHeading">
#{msgs.findAPlace}
</div>
<h:form prependId="false">
<h:panelGrid columns="2">
#{msgs.streetAddress}
<h:inputText value="#{place.streetAddress}" size="15"/>
#{msgs.city} <h:inputText value="#{place.city}" size="10"/>
#{msgs.state} <h:inputText value="#{place.state}" size="3"/>
#{msgs.zip} <h:inputText value="#{place.zip}" size="5"/>
<h:commandButton value="#{msgs.goButtonText}"
style="font-family alatino;font-style:italic"
action="#{place.fetch}"/>
</h:panelGrid>
</h:form>
</div>
<util:icon image="#{resource['images:back.jpg']}"
actionMethod="#{places.logout}"
style="border: thin solid lightBlue"/>
</ui:composition>
|
|
|
|
|
|
|