设计师与开发者,声明与过程

发布    |      

这篇帖子 总结了我偶尔听到的一些关于 JSF 的抱怨

... 使用 JSF 进行传统页面设计工作流程并不直接。在基于动作的 Web 框架中,对于有一定技术知识的 HTML 设计师来说,直接编辑 JSP 以实现外观和感觉是非常容易的。但对于 JSF 来说并非如此 -- 你离最终的 HTML 越来越远。页面上包含的组件生成 DIV 标签等。作为一名拥有 10 年以上 HTML 工作经验的开发者,我发现这是 JSF 最令人沮丧的方面之一。我们收到了来自设计公司的一系列 HTML 模拟图,集成工作已经证明是非常具有挑战性的。我想知道 JSF 是否仅仅是将工作努力从 HTML 编辑转移到组件定制。

好吧,起初可能会令人沮丧,但总的来说,我认为你的网页设计师不直接编辑 HTML 是一件好事。

原因是您不应该通过直接编辑 HTML 来实现外观和感觉。如果您这么做,那么您就绕过了整个 HTML 架构。相反,您应该为您语义化的 HTML 内容添加 CSS 选择器,并使用 CSS 来应用您的布局、外观和感觉。职责的正确分离是

  • 开发者 生产 /语义内容/
  • 设计师 生产 /样式表/

现在,大多数 JSF 组件库(以及大多数 Ajax 库)通过提供一些看起来很漂亮且可以按照内置的 主题 功能进行定制的小部件而模糊了这一点。嗯,这对于像 RichFaces 这样的产品来说是一个重要的营销特性,用户期望小部件在不进行定制的情况下看起来很漂亮,但对于严肃的开发来说,我认为这往往会导致人们走上错误的道路。这就是为什么我对 RichFaces 的第一个功能请求之一就是一个 主题,它看起来 故意 很丑,并且很容易使用 CSS 进行样式化。

在我看来,HTML 架构还有一个被低估的第三个属性

  • 内容和样式都通过 /声明式/ 表达

在我看来,这对于代码的可理解性是至关重要的。

让我们考虑一下古老的<h:dataTable>:

<h:dataTable value="#{products}" var="prod">
   <h:column>
      <f:facet name="header">SKU</f:facet>
      #{prod.sku}
   </h:column>
   ...
</h:dataTable>

此代码完美符合语义内容的描述。它是一个高度声明性的规范,

  1. 其中有一个表格,每行代表一个产品
  2. 每列都有一个表头和每个单元格中的某些内容

我真的想象不出比这更好的表达方式。考虑传统的JSP/JSTL类型方法

<table>
   <tr>
      <th>SKU</th>
      ...
   </tr>
   <c:forEach items="${products}" var="prod">
      <tr>
         <td>
            <c:out value="${prod.sku}"/>
         </td>
         ...
      </tr>
   </c:forEach>
</table>

这是一个明显更复杂的实现

  • 有5层嵌套,而相比之下是3层
  • 很难通过计数将列标题名称与内容关联起来<th><td>

更糟糕的是,它还有一个/迭代器/,因此以完全不令人满意的方式混合了两种完全不同的语言范式(声明性 vs. 过程性)。

另一方面,它并没有将裸HTML标签从我们这里隐藏起来。如果我们想编辑JSP模板来添加表现性关注点,这很容易。不幸的是,一旦我们开始在HTML中添加表现性关注点,HTML代码的可重用性就会大大降低。我们应该做的事情是添加CSS选择器。

当然,所有写得好的JSF组件都使这变得超级简单

<h:dataTable value="#{products}" 
                var="prod" 
         rowClasses="oddrow,evenrow"
        headerClass="header"
          syleClass="table products">
   <h:column>
      <f:facet name="header">SKU</f:facet>
      #{prod.sku}
   </h:column>
   ...
</h:dataTable>

现在我们的设计师可以专注于开发声明性CSS样式表,以针对我们提供的选择器,我们将可以自由地对语义HTML进行各种更改,而不会影响设计(例如,我们可以使用一些花哨的表格控件,如<rich:table>当滚动条拖动时从服务器懒加载数据,同时具有可排序、可调整大小的列和行选择。这一切都不需要一行JavaScript。

当我们考虑到数据绑定时,声明性和语义化的用户界面开发风格才能真正显示出其潜力。在传统的UI库中,树视图很痛苦。我们需要编写杂乱的Java代码来将我们的应用程序模型适应到树小部件可以理解的东西。在RichFaces中,我们只需声明树结构如何映射到我们的对象模型的/结构/。不需要Java代码

<rich:tree>

    <rich:recursiveTreeNodesAdaptor roots="#{root}" 
                                    nodes="#{dir.children}"
                                      var="dir">
                                    
        <rich:treeNode>#{dir.name}/</rich:treeNode>
        
        <rich:treeNodesAdaptor nodes="#{dir.files}" 
                                 var="file">
                               
            <rich:treeNode>#{file.name}</rich:treeNode>
            
        </rich:treeNodesAdaptor>
        
    </rich:recursiveTreeNodesAdaptor>
    
</rich:tree>

现在尝试在某个其他Web框架中做这件事!:-)

也许,你现在可以猜到为什么我会反对潮流,坚持支持JSF,而有些人正在跳上像GWT或Wicket这样的潮流。这些技术试图使用顺序代码指定自然分层的结果。就我个人而言,我根本不理解这一点。我对Hibernate、JPA、Seam、Web Beans、EJB3、jBPM等技术非常感兴趣,它们以声明性模式重新定义了以前程序性的关注点。在我看来,在用户界面这个最自然(最适宜)的领域,应该有一种趋势/远离/声明性编程,这是反直觉的。

实际上,JSF模板的纯声明性是其独特的特性之一。Facelets是我见过的第一个不需要迭代器和条件语句的模板语言。JSP、Velocity、FreeMarker、RHTML等,都鼓励逻辑和内容的混合。Facelets/JSF让您以声明性的方式表达动态内容,就像HTML或DocBook表达静态内容一样。(如果你错过了,Jacob Hookom是Java界中最聪明的人之一。)


返回顶部