备忘录

记录学习过、研究过、使用过和总结过的内容,以备不时之需

统计

留言簿(4)

积分与排名

其它

技术网站

牛人博客

阅读排行榜

评论排行榜

IoVC(转)

IoVC,一种新的编程思想


1. 概述

长久以来,在Web编程中,一直很难克服的一个问题就是:展现层与业务数据纠缠在一起,无法进行良好的解耦, 从而造成应用系统的扩展性差,维护成本高。于是,出现了所谓的MVC框架,试图以 Model-View-Control 这种非常流行的设计模式,将两者有效的隔离开来。但回顾目前主流的 Web MVC 架构,它们所做的绝大部分工作无非是:将页面中控件的值取出打包成 Java Bean;再无非就是在帮助你完成页面导航的过程中,辅助你进行页面参数的传递与分析。这样一种“简单 MVC”架构,是无法完全解决“展现层与业务数据完全解耦”这个问题的。 一旦你的需求超越了框架的能力,那么,你将面对的依然是:不得不在展现层中嵌入大量的 Script 代码,可能是Java代码片断,也可能是大量tag-lib及EL表达式的引入。

在Apusic OperaMasks 2.0中,提出了一种新的编程思想:IoVC,它能够有效解决上面提及的问题。

2. 什么是IoVC

IoVC——“Inversion of View-Control”,即“视图控制反转”,换言之:它能够把对“View(即 UI 视图)的控制力”注入到你的后台业务逻辑中。这样一来,你在编写业务逻辑的过程中,对 View 拥有足够的控制力,从而能够将展现层与业务逻辑完全的解耦。

举一个场景:页面中有一个文本输入框,它的值对应后台的一个JavaBean的属性。我们首先来看一下传统的编程模型:

页面:
<w:textField value="#{myBean.value}"/>

后台:
public class MyBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

此时,假设用户需要发生变化,我们需要设置文本输入框的tooltip,并且,它的值来自于后台 JavaBean 的另一个属性,那么,程序需要做如下调整:

页面:
<w:textField value="#{myBean.value}" 1tooltip="#{myBean.tooltip}"/>

后台:
public class MyBean {
private String value;

2private String tooltip;

public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
3public String getTooltip() {
return tooltip;
}
4public void setTooltip(String tooltip) {
this.tooltip = tooltip;
}
}

我们可以观察:在传统的编程模型下,如果页面逻辑发生变化,我们首先需要修改UI展现层,加上 tooltip="#{myBean.tooltip}" 的语句,然后,再在后台Bean中设置此属性值。

那么,在IoVC编程模型下,情况又是怎样的呢?

页面:
<w:textField 1id="txt"/>
后台:
public class MyBean {
@Bind(id="txt")
private String value;
}

如果需要扩展文本编辑框的tooltip属性,只需要:

页面:
<w:textField id="txt"/>
后台:
public class MyBean {
@Bind(id="txt")
private String value;

1@Bind(id="txt" att="tooltip")
private String tooltip;
}

在IoVC编程模型下,Web页面不需要发生任何变化,你只需要在后台 Java Bean 中写上这样一行属性声明即可@Bind(id="txt" att="tooltip") private String tooltip,甚至于你连传统的getter/setter都不需要。

换言之,在传统的编程模型下,页面美工通过网页设计工具“画”出来的页面,程序员看不懂; 而如果程序员对页面进行修改,则页面美工又无法理解; 并且,如果要更改业务逻辑,程序员需要不断的维护页面内容,最终造成页面美工与程序员无法协同工作。而在 IoVC 的编程思想下,页面美工只需要给每个组件设置一个ID,程序员在后台的业务逻辑中,便拥有对页面 UI 元素的完全控制力。Web页面在美工完成之后,程序员再也无需因为需求的变更或者逻辑的变化,而再重新维护 Web页面内容。

简而言之,IoVC是一种更好的MVC,是对MVC的一种高层次抽象。

设想一下:日后美工人员画出来的页面(只要设置了正确的ID),程序员可以拿过来直接用,并且, 如果要对页面做调整(只要不是页面元素的增加或删除),程序员可以在自己熟悉的代码中直接设置,这岂非是一种很享受的境界?

注:IoVC,Apusic OperaMasks 2.0新特性。



IoVC实例分析:Hello Duke!


1. 概述

本文用一个非常简单的例子“helloDuke",介绍 IoVC 编程模型的一种实际场景。在阅读本文前,建议您首先阅读这两篇文章:

Hello Duke!

IoVC,一种新的编程思想

在IoVC编程模型下的 HelloDuke 版本,功能没做任何增减,依然如下图所示:

但由于在程序中用到了 IoVC 思想,及 facelets 技术,因此,整个程序的目录结构更改如下:

helloDuke
--duke.gif
--greeting.xhtml
--sameName.xhtml
--WEB-INF
--web.xml
--faces-config.xml
--operamasks.xml
--classes
--helloduke
--GreetingBean.class

下面就让我们来完成此应用。

2. 应用的开发

2.1. greeting.xhtml

首先,我们来看一下老版本的 greeting.jsp是怎样的:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<h:form>
<h2>Hello, my name is Duke. What is yours?</h2>
<h:graphicImage url="duke.gif"></h:graphicImage>
<h:outputText value="#{userBean.result}"/><br>
<h:inputText value="#{userBean.name}"></h:inputText>
<h:commandButton value="sayHello" action="#{userBean.sayHello}"/>
</h:form>
</f:view>

那么,在AOM 2.0版本下,并且在 IoVC 编程思想下,greeting.xhtml又是怎样的呢?

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html">
<w:page title="helloDuke">
<w:form>
<h2>Hello, my name is Duke. What is yours?</h2>
<img src="/articles/helloduck-iovc/html_single/duke.gif" />
<h:outputText id="result"></h:outputText><br />
<w:textField id="name"></w:textField>
<w:button id="sayHello" value="sayHello" />
</w:form>
</w:page>
</f:view>

我们的注意力不要被<w:>还是<h:>所影响,我们先假设这两者都是等价的。我们主要观察<h:outputText>、<w:textField> 以及<w:button> 这三个主要UI控件的写法。我们可以看到,在新版本中,<h:outputText> 和<w:textField>并没有指定value,而<w:button>也没有指定action,但这三者都有不同的id,并且,整个页面全部都是展现层相关信息,没有任何代码片断或 EL 表达式的引入。

那么,这三者的值以及动作事件,又是怎样和后台的JavaBean关联起来的呢?

3. 后台 JavaBean 的变化

首先,我们也是先熟悉一下老版本中的 UserBean(在新版本中,它的名称改为 GreetingBean)。

package helloduke;

public class UserBean {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getResult() {
if(this.name == null || "".equals(name.trim())) return "Please input your name.";
else return "Hello " + name;
}

public Object sayHello() {
if("duke".equalsIgnoreCase(name)) return "duke";
return null;
}
}

那么,在新版本中,上述逻辑变成怎样的呢?如下所示:

package helloduke;

@ManagedBean(name="GreetingBean", scope=ManagedBeanScope.SESSION)
public class GreetingBean {

@Bind(id="result")
private String result;

@Bind(id="name")
private String name;

@Action(id="sayHello")
public Object sayHello(){
if("duke".equalsIgnoreCase(name)) return "/sameName.xhtml";
return null;
}

@BeforeRender
private void settingValues(boolean isPostBack){
if(this.name == null || "".equals(name.trim())) {
result = "Please input your name.";
}
else {
result = "Hello " + name;
}
}
}

我们可以观察到,在 result 属性上,有一个 @Bind(id="result")的 annotation 声明;同样,在name上,也有 @Bind(id="name") 的声明,而在 sayHello 方法上,则有@Action(id="sayHello") 的声明。至此,我们恍然大悟:通过这样一些声明,<h:outputText>的值自动和 result 属性关联,<w:textField>的值自动和 name 属性关联,而<w:button> 的Action事件,则和 sayHello 方法关联。

等一下,这里有个问题:针对 result 属性和 name 属性,在AOM 2.0下,连 setter/getter 方法都没有?是的,完全可以忽略。

那么,result 的值是在哪里设置的?请注意 settingValues 方法,它有一个 @BeforeRender 的声明,意思就是说:当页面在渲染前,请调用此方法。这就相当于一个回调函数,因此,对 result 属性的设置,我们就可以在此处进行处理。

好像一切都很完美,但是,还有一个问题,greeting.xhtml页面,是怎样和 GreetingBean 对应起来的?目前,你可以假设认为:这是通过命名规则获得的,但这部分内容已经超过本文所要介绍的范围, 请允许我在下一篇文章中介绍。

4. Apusic Studio的支持

我们还可以做得更好,那就是 Apusic Studio 给予的全生命周期的开发支持。

那么,Apusic Studio 对 IoVC 又提供了怎样的支持?在这里,我们提出了称为"Smart DblClick"的技术,针对任何控件对其双击,将自动弹出该控件 IoVC 支持的向导,以<w:button>为例,双击的效果如下:

看上去还不错,那么,为何不立即体验一下呢?

5. 注意

IoVC的支持仅限于 AOM 2.0 版本,并请注意 Apusic 应用服务器及 Apusic Studio的版本支持。在完成本文结束时,请使用 AOM 2.0 M1,Apusic 应用服务器 5.1 TP5,Apusic Studio 5.1 M5 版本。


posted on 2008-09-09 09:55 雪山飞狐 阅读(391) 评论(0)  编辑  收藏 所属分类: JAVA技术


只有注册用户登录后才能发表评论。


网站导航: