高级 Swing 体系结构使得开发人员能够设计比以前更复杂的显示。这些显示通常需要大量极易出错且难以维护的逻辑。对于高级 Swing 组件(例如,JTable 和 JTree),当程序逻辑使用基于单元的数据存储、编辑和渲染(常需要更多全局知识)时,常会碰到困难。可以将智能数据,或带有高级知识的数据作为单元数据持久存储在组件模型内,此单元数据提供了开发高级应用程序的必要知识。本文描述的 iData 技术建立了一个通用的体系结构,该体系结构用于将智能数据与 Swing 组件集成,同时又保留了“模型-视图-控制器(Model-View-Controller)”体系结构。通过一个紧密集成的间接方案实现了这一点,该方案将智能数据用于数据存储、数据检索间接以及显示设置间接。生成的间接对象创建了灵活且可扩展的中央位置,用来实现带有最小复杂性的复杂业务显示逻辑和交互功能。
开发人员可以获得一个开放源码 iData 工具箱,以帮助他们将 iData 体系结构集成到他们自己的项目中。该工具箱包含一个接口集合,这些接口定义了间接层、缺省实现、优化、定制编辑器与渲染器以及许多示例。请阅读 参考资料以获取到该工具箱的链接。
iData 技术的三层
iData 技术包含三层。
数据存储:iData 技术假定应用程序将数据存储在 DataObject 中。人们将 DataObject 松散定义为符合 JavaBean 的对象,它含有一些字段,以及对应的 get[FieldName]() 和 set[FieldName]() 方法。
显示组件的数据值间接:数据间接层由一个定义包含 DataObject 的对象组成。这称为智能数据或 iData 层。(注意,不要将 iData 层同 iData 技术相混淆,后者整体上是体系结构的名称。)iData 层接口定义了访问与修改 DataObject 中字段的通用方法。针对具体的需求,每个具体的 iData 层类都实现这些通用的取值(accessor)和赋值(mutator)方法。通常,iData 层实现仅仅读(get)和写(set) DataObject 中的值。然而,正如您将在示例中所看到的一样,这一间接创建了一个实现复杂逻辑的集中位置,这些复杂逻辑包括编辑验证、虚拟数据和数据修饰。iData 层被进一步细分为不可修改(只读)和可修改(读/写)数据的功能。进行这样的区分是为了简化那些带有无须编辑逻辑的复杂的不可编辑数据的接口。
根据数据定制编辑和渲染组件的显示间接:智能显示,或称为 iDisplay 层,通过使用类似于 iData 层的间接来完成智能显示。iDisplay 层为编辑和渲染 iData 层对象的组件定义了一个接口。这一 iDisplay 层定制的示例包括:通过更改单元背景颜色来显示错误条件,以及创建通用的编辑器,这些编辑器允许 iData 层实现确定最适合于编辑其数据的组件。同 iData 层一样,iDisplay 层也被细分成可修改数据和不可修改数据的功能。
这三个层结合起来创建了一个紧密集成的间接对象集,这些对象被添加到了组件模型而不是数据本身。该体系结构使得基于单元的知识成为可能,同时又可以保留 Swing 中的“模型-视图-控制器”体系结构。检索、显示和编辑数据的逻辑被封装在每个单元内的智能数据对象中。其结果是用于实现复杂用户界面显示和交互的功能上灵活和可扩展的技术。
图 1. iData 技术的完整体系结构类图
接下来,我们将讨论 iData 技术体系结构的每一层。同时,我们将构建假想的“自行车商店(Bike Shop)”应用程序的一些代码片段以演示该技术。
DataObject
如上面所提到的,人们将 DataObject 定义为符合 JavaBean 的对象,该对象含有一些字段和对应的 get[FieldName]() 和 set[FieldName]() 方法。通常,将数据字段按业务区域组合在 DataObject 中。我们的示例“自行车商店”应用程序含有一个称为 Bicycle 的 DataObject 对象,该对象有大量字段( modelName 、 manufacturer 、 price 和 cost 等等)以及相应的读(get)和写(set)方法。“自行车商店”中其它可能的 DataObject 对象有 BicycleComponent 对象(带有类似于 Bicycle 的字段)和 Purchase DataObject 对象(带有如 purchasorName 、 price 、 dateOfPurchase 等字段)。下面是“自行车商店”应用程序中 Bicycle DataObject 对象的部分代码的示例。
清单 1. 样本 DataObject
1
public
class
Bicycle
2
{
3
//
fields
4
double
price
=
...
5
String manufacturer
=
...
6
...
7
//
default constructor
8
public
Bicycle(){}
9
//
accessors
10
public
Double getPrice()
11
{
12
//
sometimes its necessary to wrap primitives in related
13
//
Object types...
14
return
new
Double(
this
.price);
15
}
16
public
String getManufacturer()
17
{
18
return
this
.manufacturer;
19
}
20
...
21
//
mutators
22
public
void
setPrice(Double price)
23
{
24
this
.price
=
price.doubleValue();
25
}
26
public
void
setManufacturer(String manufacturer)
27
{
28
this
.manufacturer
=
manufacturer;
29
}
30
...
31
}