An Introduction of ZK Composer"
m (→Introduction) |
|||
(2 intermediate revisions by one other user not shown) | |||
Line 15: | Line 15: | ||
Finally, in the Appendix, I create a diagram to show the life cycle of composers we have introduced. | Finally, in the Appendix, I create a diagram to show the life cycle of composers we have introduced. | ||
+ | <blockquote> | ||
+ | ---- | ||
+ | For further information, please refer to [[ZK Developer's Reference/MVC/Controller/Composer|ZK Developer's Reference: Composer]]. | ||
+ | </blockquote> | ||
=The Example= | =The Example= | ||
Line 246: | Line 250: | ||
* Related Article | * Related Article | ||
− | :* [ | + | :* [[Small_Talks/2007/November/The_Trilogy_of_ZK%27s_MVC_Adventure | The Trilogy of ZK's MVC Adventure]] |
− | :* [ | + | :* [[Small_Talks/2008/June/Best_Model-View-Controller_Patterns | Best Model-View-Controller Patterns]] |
− | :* [ | + | :* [[Small_Talks/2008/August/ZK_MVC_Made_Easy | ZK MVC Made Easy]] |
− | :* [ | + | :* [[Small_Talks/2008/November/ZK_With_Spring_JPA_And_A_Model-View-Controller_Pattern | ZK With Spring JPA And A Model-View-Controller Pattern]] |
Latest revision as of 10:21, 12 January 2011
An Introduction of ZK Composer -- an Example of Fusioning Component and Model
Ryan Wu, Engineer, Potix Corporation.
Dec 17, 2008
Applicable to ZK 3.5.2.
Introduction
Model-view-controller (MVC) is an architectural pattern used in software engineering. Like previous articles, we always look for the best practice for ZK to realize MVC approach perfectly. That's why we created interfaces for every ZK components in ZK 3.5.2. This article mainly introduce a new feature - "Fusion Invoker". By using it, we can separate the View and the Controller more clearly. I will create some cases to show how and why using it.
Finally, in the Appendix, I create a diagram to show the life cycle of composers we have introduced.
For further information, please refer to ZK Developer's Reference: Composer.
The Example
This is a simple example, it has a window which contains a listbox and a textbox. Now we have a list of customers' name from Class DataResource, we want to set the list into the listbox by using "model".
<syntax lang="java" > public class DataResource { //Constructor public DataResource() {...} /** * @return the ListModel */ public ListModel getCustomers() { ... return listmodel; } } </syntax> |
After choosing a customer, once the textbox get focused, it's value will change to "Dear : Customer's Name".
Historical Approach
In order to satisfy the requirements, we have several ways to do that. Following are some ways we usually use :
Using the "Use"
Extend the layout window, then use the "use" attribute :
|
|
<syntax lang="xml" > <window id="win" title="Customized Window" border="normal" use="composer.CustomWin" width="300px"> <listbox id="list" width="200px" rows="5" model="$ {win.customers}" /> <separator /> <textbox id="text" value="Click to get value" width="200px" onFocus="win.onFocusName()" /> </window> </syntax> |
<syntax lang="xml" > public class CustomWin extends Window { DataResource _dr = new DataResource(); public ListModel getCustomers() { return _dr.getCustomers(); } public void onFocusName() { final Textbox text = (Textbox) this.getFellow("text"); final Listbox list = (Listbox) this.getFellow("list"); text.setValue("Dear : " + (list.getSelectedItem() == null ? "Null" : list.getSelectedItem().getValue().toString())); } } </syntax> |
- Pros and Cons
- Pros
- Easy to understand - only attach some new method to Window.
- Cons
- The controller have to extends the component which existed in view (Window).
Composer Enhanced
Create a class extend AutowiredComposer :
|
|
<syntax lang="xml" > <window id="win" title="Auto wire Composer" border="normal" apply="composer.MyAutowireComposer" width="300px"> <listbox id="list" width="200px" rows="5" /> <separator /> <textbox id="text" value="Click to get value" width="200px" forward="onFocus=onFocusName" /> </window> </syntax> |
<syntax lang="java" > public class MyAutowireComposer extends GenericAutowireComposer { private Listbox list ; private Textbox text ; public void doAfterCompose(Component comp) throws Exception { super.doAfterCompose(comp); DataResource dr = new DataResource(); ListModel lm = dr.getCustomers(); list.setModel(lm); } public void onFocusName(Event event) { text.setValue("Dear : " + (list.getSelectedItem() == null ? "Null" : list.getSelectedItem().getValue().toString())); } } </syntax> |
- Pros and Cons
- Pros
- The class in controller don't have to extend the view component.
- Cons
- The model of listbox was set in the controller (it should be set in view).
Now - Fusion Them All
Intro Fusion Invoker
This is a new feature in ZK 3.5.2, which realize the proxy design pattern by using Dynamic Proxy Classes. In ZK's cases, it can fusion some objects' interfaces into one object then we can use it anywhere.
How to use
In the example case, we want to use $ {win.customers} to get the data from window in the zul file , so we have to fusion Window and DataResource together.
- First: Interfaces
- Window already have interfaces so we have to create DataInterface and implement it in DataResource only.
public interface DataInterface {
public ListModel getCustomers();
}
- Second: Composer
- In the life cycle of ZK, the EL will parse the $ {...} before the component be rendered, so we have to create a special composer which implement the ComposerExt Interface. Then implement doBeforeComposeChildren in ComposerExt.
abstract public class FusionComposer extends GenericAutowireComposer implements ComposerExt {
...
...
}
- Notice : if you don't know what is Composer or AutowireComposer, you might want to take a look the articles beforehand.
- Third: Usage
- Using FusionInvoker in the composer of window.
import org.zkoss.lang.reflect.FusionInvoker;
FusionInvoker.newInstance(new Object[] { ... });
The static method "newInstance" will return an object which contains the interfaces of given objects. In the case below, we can modify the code like following :
- View
<window id="win" title="Fusion Composer" border="normal"
apply="composer.MyFusionComposer" width="300px">
<listbox id="list" width="200px" model="$ {win.customers}" rows="5" />
<separator />
<textbox id="text" value="Click to get value" width="200px"
forward="onFocus=onFocusName" />
</window>
- Controller
public class MyFusionComposer extends FusionComposer {
private Listbox list;
private Textbox text;
public void doBeforeComposeChildren(Component cmp) throws Exception {
super.doBeforeComposeChildren(cmp);
DataResource dr = new DataResource();
Object obj = FusionInvoker.newInstance(new Object[] { cmp, dr });
//set the new object to original component's name then we can use it by EL
cmp.setVariable(cmp.getId(), obj, true);
}
public void onFocusName(Event event) {
text.setValue("Dear : "
+ (list.getSelectedItem() == null ? "Null" : list
.getSelectedItem().getValue().toString()));
}
}
- Pros and Cons
- Pros
- Better separate view and controller
- Cons
- Must create interface for class we want to fusion
Appendix
- Life cycle of Composer
- Related Article
- Download
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |