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

回到顶部