当前页面位置: » 丰搜网 » 文档中心 » 详细内容
在swing中使用高级的mvc和pojos
在swing中使用高级的mvc和pojos-介绍tikeswing框架作者:tomi tuomainen 2005年6月20日翻译:waitu版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
英文原文地址:
http://www.
javaworld.com/
javaworld/jw-06-2005/jw-0620-tike
swing.
html中文地址:
http://www.matrix.org.cn/resource/article/43/43731_
swing_mvc_pojos.
html关键词:
swing mvc pojos
摘要:tike
swing 是一个开放源码的
swing框架,它提供了一个高度mvc(模型-
视图-控制器)
模式的体系结构并且使
swing组件的使用非常简单。它通过将
视图组件和
javabeans直接连接来支持pojo编程
模式。在这篇文章中将阐述tike
swing的特点,并且将示范怎样使用这个
框架创建一个清晰的mvc的系结构。(2,400个英文单词;2005年6月20日)
最近,在
java社区里面,丰富的互联网应用程序(rias)的兴起成为一个热点话题。另外一些新的技术,像
ajax(异步的
javascript和
xml),macromedia flex, 和laszlo,以及与
java web start一起使用的虽旧而好的
swing,它们都被提议作为ria技术。
然而,
java社区里面的很多人对
java基础类库(jfc)和
swing提出了批评。
swing在建立高度mvc
模式的客户端体系方面不能提供太多的帮助。任何合理的
服务器应用程序返回传递的对象,或者称为简单初始
java对象(pojos),把它传递到客户端的技术证明了
j2ee世界的窘境。从pojo范围映射到
swing组件需要太多的手动的代码,反之亦然。
同样的,实现
swing其他的功能,就像
线程句柄和验证域,也是很费力的事情。而且有时候
swing组件很难使用:创建一个合适的表格或者树模型通常需要很多的编码,而且需要深入的研究
swing编程文档中的api。
tike
swing 是一个开放源码的
swing框架,它提供了一个高度mvc(模型-
视图-控制器)
模式的体系结构并且实现了模型,组件和控制器通信的自动化。它简化了
swing组件的使用,并通过将
视图组件和
javabeans直接连接来支持pojo编程
模式。
这篇文章将示范怎样使用tike
swing创建一个清晰的mvc的体系结构。也将阐述建立tike
swing组件的原则,并简单描述在这个
框架中包含的最佳体验和机制。
mvc体系结构众所周知,mvc范例是推荐的图形用户界面发展的基本体系。它还有很多的可用的变种,就像mvc++, hmvc (hierarchical mvc), mvc model 2, mvc push, and mvc pull,它们每一个都有些不同之处。tike
swing基于下面的mvc原则:
●model 模型:
o来自一些真实世界或者系统的抽象
o包装其数据和函数
o在数据改变时通知观察者 (编者注:observer, 设计
模式术语)
●view
视图:
o系统的用户界面
o依附于模型并通过显示界面将它的内容显示出来
o在模型改变时自动刷新受到影响的部分
●controller 控制器:
o控制应用程序的流程
o接受用户的输入,并根据用户输入指导模型和
视图完成任务
下面的图表表示了tike
swing中mvc的类结构。
图 1. 一个使用tike
swing的应用的mvc类图
类mymodel, myview, 和mycontroller由一个使用
框架的应用来实现。mymodel和mycontroller扩展了tike
swing的ymodel 和ycontroller类。一个
视图的类可以是任何实现了yicomponent接口的
java.awt.component。
tike
swing在装配类结构的时候不使用任何的配置文件。当ycontroller,ymodel和
视图组件提供了要求的功能特性的时候,扩展适当的类已经足够了。下面讲述如何使用tike
swing来实现模型、
视图和控制器类。
模型tike
swing的模型是一个为实现
视图而包含数据的
javabeans组件。一个模型类可能包含嵌套的
javabeans,数组,映射和集合。和标准
javabeans中要求的一样,所有模型的类变量必须有适当的get和set方法。从这种意义上说,tike
swing就像很多的网络应用程序
框架那样工作,所以在不同的技术之间重用模型类是很容易的。
ymodel是模型的基类。它提供了报告数据改变的方法。当触发了一个事件的时候,
框架会更新与之相连的
视图。在分布式环境中,一个模型类有从
服务器应用程序中得到pojos的方法(通常是从隐藏了业务服务的实现细节的业务代理中)。模型自身存储了pojos,且它有责任通知观察者。在有些mvc的体系结构中,一个控制器类和
服务器通信,pojos存储在控制器中。然而,tike
swing分离出ymodel类的方法有下面的优势:控制器专著于流程,另外的方法(操作模型数据的)可以被加在客户端。ymodel遵循了传统的mvc
模式,所以mvc中类的责任就清晰地分开了。
下面的代码演示了模型类如何通过给定的参数找到customers。模型的类变量name和id是搜索标准,customers是包含搜索结果的customer pojos的集合。findcustomers()方法通过customerservicedelegate从
服务器应用程序中得到customers。当方法notifyobservers()激活时,
框架会自动更新相连的
视图。
public class findcustomermodel extends ymodel {
private string name;
private string id;
private collection customers;
private customerservicedelegate delegate = new customerservicedelegate();
public void findcustomers() {
setcustomers(delegate.findcustomers(id, name));
notifyobservers("customers");
}
public void setcustomers(collection customers) {
this.customers = customers;
}
public collection getcustomers() {
return customers;
}
public void setid(string id) {
this.id = id;
}
public string getid() {
return id;
}
public void setname(string name) {
this.name = name;
}
public string getname() {
return name;
}
}视图tike
swing视图是包含其他
swing组件的
swing组件。通常,一个
视图类是一个面板,一个对话框,或者一个帧,它们建立了子组件并将之添加到自身(就像在通常的
swing开发环境中一样)。然而,tike
swing应用程序中使用的所有组件都必须实现适当的接口以连接
框架的mvc体系结构。幸运的是,
框架包含一个很大的为了这种目的已经实现的组件的集合。
一个特殊的名字必须赋予一个
视图组件,这样
框架就能在组件和被命名的模型类变量之间复制数据。命名的惯例和其他的用于网络应用程序
框架的和apache beanutils库(它通常用于
框架的执行)类似。下面是支持的命名格式:
●简单的: 直接连接到模型域的组件;例如,field1
●嵌套的:连接到模型内部的
javabeans域的组件;例如,field1.field2
●
索引的:连接到模型内的数组域的组件;例如myarray[1]
●映射的:连接到模型内的映射域组件;例如,myhashmap(“foo”)
●组合的:通过结合符号连接到模型的内部域的组件;例如,field.myarray[1].myhashmap["foo"]
除了模型类的get和set方法外,
视图类必须为每一个
视图组件建立一个get方法。
下面的例子是为findcustomermodel建立的
视图类。它使用了扩展了基础
swing类的tike
swing组件(从jlabel到ylabel,jtextfield到ytextfield,等)。例子的代码和标准的
swing视图很像,只有setmvcnames()方法包含了tike
swing特有的代码。依照上面讲述的原则,它设定了模型组件的连接。resulttable列通过ycolumn对象与customers集合中的pojo域相连。findbutton不显示任何从模型得到的数据,但是mvc的名字是为tike
swing的事件句柄设定的(以后再讲)。
public class findcustomerview extends ypanel {
private ylabel idlabel = new ylabel("id");
private ylabel namelabel = new ylabel ("name");
private ytextfield idfield = new ytextfield();
private ytextfield namefield = new ytextfield();
private ypanel criteriapanel = new ypanel();
private ytable resulttable = new ytable();
private ybutton findbutton = new ybutton("find");
public findcustomerview () {
addcomponents();
setmvcnames();
}
private void setmvcnames() {
idfield.getyproperty().put(yicomponent.mvc_name,"id");
namefield.getyproperty().put(yicomponent.mvc_name,"name");
resulttable.getyproperty().put(yicomponent.mvc_name,"customers");
findbutton.getyproperty().put(yicomponent.mvc_name,"findbutton");
ycolumn[] columns = {
new ycolumn("id"),
new ycolumn("name")};
resulttable.setcolumns(columns);
}
private void addcomponents() {
this.setlayout(new borderlayout());
this.add(criteriapanel, borderlayout.north);
idfield.setpreferredsize(new dimension(100, 19));
namefield.setpreferredsize(new dimension(100, 19));
criteriapanel.add(idlabel);
criteriapanel.add(idfield);
criteriapanel.add(namelabel);
criteriapanel.add(namefield);
criteriapanel.add(findbutton);
this.add(resulttable, borderlayout.center);
}
public ytextfield getidfield() {
return idfield;
}
public ylabel getidlabel() {
return idlabel;
}
public ytextfield getnamefield() {
return namefield;
}
public ylabel getnamelabel() {
return namelabel;
}
public ytable getresulttable() {
return resulttable;
}
public ybutton getfindbutton() {
return findbutton;
}
}现在,无论任何时候用户修改idfield 或者namefield,改变的地方都会自动更新到模型。而且,当notifyobservers()在 findcustomermodel中调用的时候,
框架会更新变化到resulttable。然而,为了匹配结构,一个控制器必须是特定的。
控制器tike
swing的控制器通过调用
视图和模型的方法来处理应用程序的流程。一个控制器的类必须扩展ycontroller,它提供了控制关系中的必要的方法。通常,控制器也创建
视图和模型对象,但是要注意的是,几个
视图和控制器可能共享相同的模型对象。
一个控制器类可能有好几种方法来获取用户事件。tike
swing组件包括基于反射的事件句柄:一个事件可以通过实现带有合适签名的方法而在控制器类中得到处理。例如,当用户点击按钮的时候,一个mvc名字为mybutton的按钮在控制器中会调用mybuttonpressed()方法(如果实现了的话)。这与标准的
swing事件监听接口和适配器相比是很方便的。
另一方面,事件方法签名中的字符在编译器中是不显示的,但是
swing适配器类的情况是:编译器不说明public void actionperformed是一个新的或者重载的方法。因为监听接口经常需要许多空的方法的执行,基于反射的简单的事件处理一定会加快代码的进程。作为选择,你可以在
视图类中使用标准的监听者,而手动调用控制器的方法。
下面的代码是findcustomermodel和findcustomerview的控制器的一个例子。控制器通知mvc的结构是通过调用setupmvc()方法和使用findbutton 来处理基于反射的事件。
public class findcustomercontroller extends ycontroller {
private findcustomerview view = new findcustomerview();
private findcustomermodel model = new findcustomermodel();
public findcustomercontroller() {
super();
setupmvc(model, view);
}
public void findbuttonpressed() {
model.findcustomers();
}
}ycontroller是tike
swing中功能的核心。除了上面讲述的特点之外,它还提供了很多有用的方法能用于:
●捕获特定域的改变
●在控制器中发送和接收信息
●跟踪用户的修改
●取消用户的改变
●捕获模型抛出的异常
●验证域值的有效性
tikeswing组件tike
swing基于这样一种思想,组件负责处理在模型中相关联的对象。这种思想以前在sun的《
swing指南》中的wholenumberfield演示中有体现。组件必须知道怎样在屏幕上面显示模型的值和怎样转换用户给定的值到模型中。
框架现在提供了一个足以使大多数应用程序使用的组件的集合。
框架组件的行为就像基础的
swing组件,当然了,你必须阅读
java文档以理解组件和mvc类的交互(组件可以处理什么类型的模型域和它提供了什么事件的方法)。tike
swing组件也提供了其他的特点和简洁的开发。例如,一个pojos的集合可以在不创建任何特殊的组件模型的情况下直接使用于ytable和ytree。
tike
swing组件基本上可以是任何的
java.awt.component。然而,一个组件必须实现适合的tike
swing接口,那样它就能被集成到
框架的mvc的体系结构中。它通常包含扩展了带有四个简单方法的标准
swing组件,因此这将是一个比较琐碎的任务。下面的代码是一个例子。和模型的集成是通过getmodelvalue() 和setmodelvalue()方法实现的。组件值的改变的通知是addviewlistener()方法实现的。为了能在
框架内部使用,必须实现getyproperty()方法。
下面的代码演示了一个支持integer对象的简单文本域:
public class yintegerfield extends jtextfield implements yimodelcomponent {
/** gets value of this field for the model. */
public object getmodelvalue() {
try {
return new integer(gettext());
} catch (exception ex) {
return null;
}
}
/** sets the model value into this field. */
public void setmodelvalue(object obj) {
if (obj == null) {
settext("");
} else {
settext(obj.tostring());
}
}
/** notifies the framework when the component value might have changed. */
public void addviewlistener(final ycontroller controller) {
this.addfocuslistener(new focusadapter() {
public void focuslost(focusevent ev) {
controller.updatemodelandcontroller(yintegerfield.this);
}
});
}
// the rest is for the framework internal use,
// the implementation must be copied to each new component:
private yproperty myproperty = new yproperty();
public yproperty getyproperty() {
return myproperty;
}
}其它的特点除了mvc的体系结构,tike
swing还有很多协助进行
swing开发的其它的特点。这些特点不是什么革命性的东西,它们可以在很多已经实现的
swing应用程序上面看到。但是,没有必要重新发明轮子,一些最好的
swing开发的体验包含在了这个
框架中。
tike
swing支持控制器多层结构的创建,就像在hmvc和mvc++中描述的那样。
框架提供了使控制器之间实现父子关系的方法,这使类结构更协调和清晰。这种关系又助于和客户应用程序通信,而且可以用来和众所周知的设计
模式集成。tike
swing支持任务链
模式,这种
模式中,一个请求直到控制器对象才处理事件时才被传递。tike
swing也支持observer/observable
模式:一个控制器类可能传递一个能被所有已经注册了的控制器处理的事件。
tike
swing也包含一种为tabbed panes检索慵懒数据(lazy data)的机制。在一个分布式的系统中,一下子从
服务器得到所有tabs的数据可能需要很长的时间。为了优化性能,有必要只在每个tab被选择后才为其检索一次数据。
框架提供了简化这种功能的机制,所以代码的复杂性,特别是在嵌套的tabbed panes里面,已经减少了许多。
当用户触发一个事件,可能导致刚修改的数据丢失的时候,一些应用程序会检查未被保存的改变。这些事件可能是下面的例子,关闭窗口,改变tabbed pane的tab的焦点,或者选择一个表格的列。tike
swing 提供了进行检查特殊事件的工具。tike
swing也会自动弹出“是否保存更新?”的对话框,并委托一个控制器方法来保存。另外,
框架记得
视图在特定时刻的状态,可以在稍晚的时候返回那种状态。这就意味着
框架可以在不取得原始数据的情况下取消改变。
当两个或更多的组件执行相同的函数的时候,
swing的行为被证明是有用的。一个action对象提供了集中的事件处理,但是如果行为用于单独的类的话,代码会因为增加的耦合而更加复杂。tike
swing包含了一个集中处理产生事件的场所,因此一个动作可以用于不同的
视图类而且不会直接耦合。
swing组件只能由事件分派的
线程进行创造,修改和查询,这使
swing应用程序中的
线程处理更加复杂。《
swing指南》中说
swingworker类对这个问题提供了帮助。tike
swing封装了
swingworker,并且使
线程处理更加简单。例如,一些应用程序在进行远程调用或i/o操作的时候不会死锁。使用tike
swing,在进行这样的操作时可以弹出一个可管理的,可重画的对话框,而且实现只需要几行代码。
summary 总结由于有了高级的mvc和pojo的支持,tike
swing简化了
swing的开发。使用tike
swing是合理的,特别是在分布式环境中,由
服务器应用程序返回的pojos可以直接用于模型类,这个类直接连接到
视图类。这个
框架也包含了一些解决复杂开发问题的最佳实践。因此,tike
swing减少了为
swing客户所写的代码,加快了开发。
tike
swing自身提供了丰富的平台无关的用户界面库。
swing开发已经成为这几年一些重要的ide的一部分,所以可见即所得的设计,单元
测试和调试已经被广泛地支持。早先的工作站上性能的问题现在已经不是问题了,
java的网络应用也简化了分布式的
java应用程序。与网络应用程序的
框架相比,
swing提供了更加友好的用户界面,没有
javascript支持的问题,通过工作站上面的客户逻辑简化了网路上的通信量。
对
swing复杂性的批判依旧是正当的。但是,使用像tike
swing的高级mvc
框架,复杂性就减少了,
swing就转换成了一个生产力很高的客户端技术。我希望
java社区为
swing开发和采用一个
开源的mvc
框架,这将使其成为ria技术中的一员。可能像
spring似的肥客户端技术更加接近目标。与其等待,不如请出tike
swing,体验一下它是如何适应你的ria工程的。
关于作者tomi tuomainen是entra e-solutions的顾问和架构师,他从1999年开始使用
j2ee应用系统和
java框架。他是计算机科学的理学硕士和sun的认证企业架构师。他的兴趣(
java之外的)在于音乐,吉他和体操训练。你可以说他是芬兰最强的it顾问之一。
资源 ●最新版本的tike
swing(包括类路径,源代码,用户指南和
javadoc api的必需的jar文件)可以在这里下载:
http://sourceforge
.net/projects/tike
swing●关于tike
swing遵循的mvc范例的基本信息:
http://ootips.org/mvc-pattern.
html●就像
javabeans规范中说的那样,tike
swing的模型对象必须包含get和set方法:
http://
java.sun.com/products/
javabeans/docs/spec.
html●
swing指南:
http://
java.sun.com/docs/books/tutorial/ui
swing/index.
html●hmvc范例分解了客户端为父子mvc层,这也能用于tike
swing。阅读 “hmvc:用于开发强壮客户端层的层次
模式,” jason cai, ranjit kapila, and gaurav pal (
javaworld, 2000年7月),可获取更多信息:
http://www.
javaworld.com/
javaworld/jw-07-2000/jw-0721-hmvc.
html●mvc++范例共享了hmvc的关于控制器层次的想法:
http://www.cs.uta.fi/~jyrki/ohto02/mvc.ppt
●apache beanutils库,包含了能用于
javabeans域(在tike
swing中使用了)引用的格式的描述:
http://jakarta.apache.org/commons/beanutils/api/index.
html●和tike
swing有共通之处的
spring肥客户端工程:
http://www.
springframework.org/
spring-rcp
●关于
swing开发的更多文章,浏览
javaworld的awt/
swing部分的论题
索引:
http://www.
javaworld.com/channel_content/jw-awt-index.s
html●关于ui设计的更多文章,浏览
javaworld的user interface design部分的论题
索引:
http://www.
javaworld.com/channel_content/jw-ui-index.s
html●最后,浏览
javaworld论题
索引的development tools部分:
http://www.
javaworld.com/channel_content/jw-tools-index.s
html