Eclipse设计实现可重用的SWT构件
2007-11-19 10:44:36 来源:论坛整理 作者:翁长河 点击:
本文从创建一个简单的SWT Tree Table开始,引入可重用的用户界面构件这个开发人员普遍关心的问题,然后分析Eclipse的用户界面的一些设计模式,循序渐进的向读者展示了如何设计实现一个精巧的高度可重用的TreeTable构件,最终通过增加一些扩展的功能显示了该构件强大的可扩展能力和灵活性。
TestWindow的运行结果和图2完全相同。这里的TreeTable构件,使用非常简单,你可以像使用一个普通的SWT构件一样使用它,并且TreeTable的实现使用了一系列细粒度的控制器,读者可以参考图8的类图。
图8:TestWindow中TreeTable的构成

从图8中我们可以看出,虽然我们新建了5个类,多于在第一部分创建的2个类,但是很好的隔离了行和每个列的控制,结构具有松散耦合的特点,具有很好的扩展性,我们将在第四部分演示如何扩展。本部分的示例代码参见附件中的test_1.0.0.jar。 这种细粒度的控制可以完全的分散程序的功能,也就大大简化了代码的结构,清晰易读,具有自解释的功能,大量的细粒度的类和方法,本身就是最好的注释,这样的代码具有很强的可维护性,在大规模的项目中,还有助于快速定位和解决问题。
也许读者已经注意到EmployeeTreeTableAdapter中的判断代码,如果情况再复杂一点,我们就需要为三种数据类型分别构建3个Adapter,这里我们只使用一个,把它简单化处理了。这样的判断不能避免,但是我们可以通过将判断转移到适配器工厂,可以只要判断一次,将不同的逻辑分散于不同的适配器中,避免重复的判断代码,重复的代码维护起来很不方便。
有经验读者可能会问,既然如此强调可重用性,为什么不为TreeTable建立一些扩展点,用添加扩展的方法去控制该实例的行为呢?就本文的示例而言,我们的考虑是这样的:
1 Eclipse的PDE中扩展编辑器功能较弱,基本无法进行有效的语法检查和正确性校验(初学者也许有过在plugin.xml里面写错一个字母而浪费半天时间调试的经历)。
2 对于这样一个具体的构件,用扩展点来做就未免有点问题扩大化,将会牺牲了程序的简洁和优美,降低开发速度。
3 扩展点虽然可以实现松耦合,但是隔断了代码之间的关联关系,为程序的编写带来不便。
实际上,Eclipse程序员会有一种倾向,有人会习惯而自然的为所有可重用的组件添加扩展点,期望用扩展的方法来重用代码。从而造成扩展点过多,程序结构过于复杂。而我们认为最适合的就是最好的,扩展点的约束和控制条件都相对较弱,过量的使用扩展点和扩展会破坏程序的连贯性,对开发过程反而有害。因此我们不建议在Eclipse项目中滥用扩展点,Eclipse的扩展点机制可以增强程序的整体可延伸性,但是细粒度的局部的构件,采用面向对象的传统方法实现重用,无论从代码的可读性和开发的效率来看,都是非常适合的。
5.增加TreeTable构件的功能
现在我们将向您展示该构件超强的扩展能力,我们将轻松的实现TreeTable的列排序的功能,然后为特定的行增加背景色。上文的TreeTable实现中,相关的接口都已经具备了,这里我们将实现这些扩展能力。限于篇幅,第一部分中所提到的很多扩展的功能,有兴趣的读者可以参考我们的实现完成。
增加列排序功能
我们的列排序的接口已经提供了对排序的基本支持,详见图9。
图9:IField支持排序的接口

compare方法将返回两条数据(Table中的两行在此列的Cell的值)比较后的值来决定这两行的顺序。getDefaultDirection方法将表示该列的排序是升序还是降序。由于设计上的精巧,我们不需要为每个IField实现该接口,我们只需要在AbstractField中实现这两个方法,代码参见清单13,有特殊需要的子类可以重载它们。
清单13:AbstractField中支持排序的方法
public int compare(Object obj1, Object obj2) {
if (obj1 == null || obj2 == null) {
return 0;
}
if (getValue(obj1) != null&&getValue(obj2)!=null)
return getValue(obj1).compareTo(getValue(obj2));
else
return 0;
}
public int getDefaultDirection() {
return 0;
} |