ZK官方MVC原理详解(一)
本文内容纲要:ZK官方MVC原理详解(一)
作者:Henri Chen, Principal Engineer
ZK的团队一直试图在zk中实现MVC方法最佳实践,在这篇文章中我们将会讨论zk中MVC编程,我们还详细的介绍在zk中提供三个工具类和三个帮助方法,将为开发者在程序中编写Model-View-Controller模式更方便、更简单。此外、还将最初将Java写在zscript中,提供了最佳途径来重构原型代码。
我将使用一个简单的例子来说明这些工具类和帮助方法实力。
假设:两个文本框:一个是姓、一个是名,当这两个文本框变化时候而另外一个全名要自动更新。
第一种方式:
composer1.zul
<window title="composer1 example" border="normal" width="300px" apply="MyComposer1"> <grid>
<rows>
<row>First Name: <textbox id="firstName" forward="onChange=onFirstName"/></row>
<row>Last Name: <textbox id="lastName" forward="onChange=onLastName"/></row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
</window>
MyComposer1.java
public class MyComposer1 implements Composer {
private Textbox firstName;
private Textbox lastName;
private Label fullName;
public void doAfterCompose(Component win) throws Exception {
firstName = (Textbox) win.getFellow("firstName");
lastName = (Textbox) win.getFellow("lastName");
fullName = (Label) win.getFellow("fullName");
//定义和监听事件登记 define and register event listeners
win.addEventListener("onFirstName",
new EventListener() {
public void onEvent(Event event) throws Exception {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
});
win.addEventListener("onLastName",
new EventListener() {
public void onEvent(Event event) throws Exception {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
});
}
}
在这里composer1.zul定义了程序的页面视图部分,而MyComposer1.java在程序生命周期上window创建时候介入,主要负责负定义和注册监听事件。然而,不管怎么样!
当我添加更多事件代码时候,我们会不停的添加addEventListener这样重复的代码。但是我们怎么去除这烦人的代码呢?
org.zkoss.zk.ui.util.GenericComposer 辅助类帮助我们解决这个问题
composer2.zul
<window title="composer2 example" border="normal" width="300px" apply="MyComposer2">
<grid>
<rows>
<row>First Name: <textbox id="firstName" forward="onChange=onFirstName"/></row>
<row>Last Name: <textbox id="lastName" forward="onChange=onLastName"/></row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
</window
MyComposer2.java
...
public class MyComposer2 extends GenericComposer {
private Textbox firstName;
private Textbox lastName;
private Label fullName;
public void doAfterCompose(Component win) throws Exception {
super.doAfterCompose(win);
//得到zk组件
firstName = (Textbox) win.getFellow("firstName");
lastName = (Textbox) win.getFellow("lastName");
fullName = (Label) win.getFellow("fullName");
//all addEventListener and new EventListener() codes are removed
}
public void onFirstName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
public void onLastName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
}
该MyComposer2类继承GenericComposer,写事件侦听器的代码直接写onXxx,对GenericComposer类doAfterCompose方法会为你做的繁琐的addEventListener
按照惯例,这是一个典型的Design by Convention方法,与onXxx命名模式的所有方法将会自动被视为事件处理,而且自动帮你注册这些事件。
对于一个典型的互动丰富的应用程序,事件处理中通常需要访问数据模型bean和操纵UI组件与最终用户交互。获得这样的组件引用和数据bean是在事件处理常见的做法。所以为什么在MyComposer2中大量使用getFellow()方法,另一方面,这些都是在一个框架可以发挥作用,为什么不把这些组件和这些数据beans绑定呢?
因此,这里来了org.zkoss.zk.ui.util.GenericAutowireComposer 工具类扩展GenericComposer类并添加了auto-wire的特点。
composer3.zul
<window title="composer3 example" border="normal" width="300px" apply="MyComposer3"> <grid>
<rows>
<row>First Name: <textbox id="firstName" forward="onChange=onFirstName"/></row>
<row>Last Name: <textbox id="lastName" forward="onChange=onLastName"/></row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
</window>
MyComposer3.java
public class MyComposer3 extends GenericAutowireComposer { private Textbox firstName; //auto-wired
private Textbox lastName; //auto-wired
private Label fullName; //auto-wired
//all getFellow() codes are removed
public void onFirstName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
public void onLastName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
}
在来看看MyComposer3中它继承了GenericAutowireComposer ,所有的getFellow方法都去除掉了。
对GenericAutowireComposer类doAfterCompose方法为你自动注入适当的组件,
事实上,如果在你的zul文件中你定义适当的变量解析器(variable resolver),例如Spring变量解析器(variable resolver),则GenericAutowireComposer也会为你的Spring bean注入
以下是这的一些片断代码。讨论的ZK +spring请参考另一篇文章。
spring-config.xml
...<bean id="taskDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
...
taskEditor.zul
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window id="taskWnd" title="Task Editor" border="normal" width="500px" apply="TaskEditorComposer">
<grid>
<rows>
<row>Title: <textbox id="title"/></row>
<row>Description: <textbox id="description"/></row>
</rows>
</grid>
<button id="saveBtn" label="Save" forward="onClick=onSaveTask"/>
</window>
TaskEditorComposer.java
public class TaskEditorComposer extends GenericAutowireComposer {
private TransactionProxyFactoryBean taskDao; //Spring bean auto wired
private Textbox title; //auto wired
private Textbox description; //auto wired
private Button saveBtn; //auto wired
public void onSaveTask(Event event) {
Task currentTask = componentScope.get("task");
currentTask.setTitle(title.getValue());
currentTask.setDescription(description.getValue());
taskDao.update(currentTask);
}
...
}
由于在zscript中我们可以直接使用隐式对象,同样的GenericAutowrieComposer 也支持隐式对象甚至zscript中的alert() 方法也支持。下面composer4就是个例子,当firstName变化时,它就会请求self(应用composer时候的隐式对象,这里也就window实例)
改变他的标题并且弹出alert消息框,这也带来另外一个好处,为zscript代码重构到java代码上来提供更方便更轻松的途径。你可以复制和粘贴,并做一些轻微的修改,即使你已经用了一些这样用来隐式对象存在只在zscript。查看一下composer4-1.zul使用zul和zscript,在看看MyComposer4.java中的onFirstName() 和onLastName()方法有什么类似吗?
composer4.zul<window title="composer4 example" border="normal" width="300px" apply="MyComposer4">
<grid>
<rows>
<row>First Name: <textbox id="firstName" forward="onChange=onFirstName"/></row>
<row>Last Name: <textbox id="lastName" forward="onChange=onLastName"/></row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
</window>
MyComposer4.java
public class MyComposer4 extends GenericAutowireComposer {
private Textbox firstName;
private Textbox lastName;
private Label fullName;
public void onFirstName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
((Window)self).setTitle("First Name changed");
alert("First Name changed to "+firstName.getValue());
}
public void onLastName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
((Window)self).setTitle("Last Name changed");
alert("Last Name changed to "+lastName.getValue());
}
}
composer4-1.zul (quick prototyping)
<window title="composer4-1 example" border="normal" width="300px">
<attribute name="onFirstName"><![CDATA[
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
((Window)self).setTitle("First Name changed");
alert("First Name changed to "+firstName.getValue());
]]></attribute>
<attribute name="onLastName"><![CDATA[
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
((Window)self).setTitle("Last Name changed");
alert("Last Name changed to "+lastName.getValue());
]]></attribute>
<grid>
<rows>
<row>First Name: <textbox id="firstName" forward="onChange=onFirstName"/></row>
<row>Last Name: <textbox id="lastName" forward="onChange=onLastName"/></row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
</window>
知道现在!在前面几个例子中zul文件中总是使用forword来分别触发window中firstName和lastName文本框中OnFirstName和OnLastName事件来转向他们的onChang事件,毫无疑问!这个MVC使得每个组件重复forward,我们还能不能消除forward的属性呢?
org.zkoss.zk.ui.util.GenericForwardComposer 这个工具类满足这一需求,请注意,GenericForwardComposer继承GenericAutowireComposer类,因此它有它的父类(GenericAutowireComposer)和祖父类(GenericComposer)所有功能
composer5.zul
<window title="composer5 example" border="normal" width="300px" apply="MyComposer5"> <grid>
<rows>
<row>First Name: <textbox id="firstName"/></row><!-- forward is removed -->
<row>Last Name: <textbox id="lastName"/></row><!-- forward is removed -->
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
</window>
MyComposer5.java
public class MyComposer5 extends GenericForwardComposer {
private Textbox firstName;
private Textbox lastName;
private Label fullName;
//onChange event from firstName component
public void onChange$firstName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
//onChange event from lastName component
public void onChange$lastName(Event event) {
fullName.setValue(firstName.getValue()+" "+lastName.getValue());
}
}
当我们写composer继承于GenericForwardComposer的时候,你必须按照一些命名规则来定义你的事件侦听器方法,
这是另一种Design by Convention模式实现。例如MyComposer5.class,被命名onchang$firstName事件监听读成为“onChange event from the firstName component”于firstName组件中的onChang事件
GenericForwardComposer会帮助你forward事件到应用组件,正如你可以看到,forword在compser5.zul毫无疑问地移除掉,这样我们可以完全分离了页面层zul和业务逻辑控制层。
哎呀!写不完!分两页写!翻译的不好!希望大家拍砖!如果那里不对希望大家帮我纠正!我主要是为了自己不再翻英文看!烦死了!
本文内容总结:ZK官方MVC原理详解(一)
原文链接:https://www.cnblogs.com/xiaopen/archive/2011/03/29/zkMVC_1.html
以上是 ZK官方MVC原理详解(一) 的全部内容, 来源链接: utcz.com/z/296555.html