科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道Eclipse设计实现可重用的SWT构件

Eclipse设计实现可重用的SWT构件

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文从创建一个简单的SWT Tree Table开始,引入可重用的用户界面构件这个开发人员普遍关心的问题,然后分析Eclipse的用户界面的一些设计模式,循序渐进的向读者展示了如何设计实现一个精巧的高度可重用的TreeTable构件。

作者:翁长河 来源:论坛整理 2007年11月21日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共6页)

 可重用问题的提出

  虽然上面的示例中SWT的这种设计模式看上去很优美,然而经验使我们对EmployeeLabelProvider中getColumnText方法中的复杂的条件判断还存在疑惑。难道只能这样无止境的判断下去吗?为什么不能直接的操纵每一列的数据呢?对于简单的需求,示例的说法相对容易,这么简洁的代码,你都不需要加任何的注释,然而一旦面对现实世界中纷繁复杂的业务系统,你的代码势必会迅速的膨胀,例如,仅对这个具体的表格来说:

  如果有些行的某些列要求显示特殊的图标,你不得不在EmployeeLabelProvider 的getColumnImage方法中重复大量的判断;

  如果调整了列之间的顺序,所有判断的地方都需要重新修改;

  如果需要为每个不同的列增加不同的编辑功能(如text,Combo,Dialog),你也会增加很多相似的判断;

  如果某些列被要求是可以被隐藏的…

  如果希望给不同的列增加过滤显示的功能或者为某些列增加排序的功能…

  如果某些特定的行或者列需要增加显示背景色…

  如果某些行需要增加特定的右键菜单…

  如果某些行可以打开特定的编辑器或者对话框…

  好吧,这些事情是我们经常会遇见的,我打赌如果你就按部就班的把这些功能实现后你的ContentProvider和LabelProvider中的代码一定混乱不堪,经过岁月的洗礼和需求的频繁变更,我们的代码迅速膨胀,就像Martin Fowler所说,到处散发出“臭味”,有经验的读者一定在项目中见过长达数千行的ContentProvider和LabelProvider类,这些类是如此的庞大以致于后期的维护和修改变得异常的困难。

  何况,如果系统中存在数十个这样的不同的复杂的table,尽管你可以通过快速的拷贝,粘贴,重命名和简单的重构在几天内完成数十个表的工作,然而面对需求的变化,事情就变得越发的复杂,你不得不每天在需求的变化中,重复的修改这些数不清的ContentProvider和LabelProvider,是谁让这个世界如此疯狂?我们一定经历过这样疯狂拷贝粘贴的年代,面对很多类似的表格,我们经常会重复的创建无数的table,给他们增加很多相似的功能,当你沾沾自喜的数着自己一天又编写了多少个Java类,创建了多少个表格的时候,你是否想过,为什么这些Java类看上去这样的相似,难道重复的拷贝相似的代码不能让你思考一些更好的办法吗?

  是时候了,是时候我们重新开始,创建一个高度可重用的TreeTable构件了,这个构件还要具有很强的扩展能力。为什么要可重用?因为你会不止一次的用到它。为什么要扩展?因为它不一定完全满足你的需求。如果我们编写程序的时候时刻有这样的想法,我相信我们的程序一定会比以前提高很多,永远不要假定你的代码是封闭的,要时刻准备着被重用。

  不要认为这样的想法是多余的,笔者对国内外多个大型业务系统有所接触(财务,税务,零售等),发现这些系统无一例外的构建在领域通用的框架之上,这些框架面对特定领域的问题的集合,提供了快速构建和灵活扩展的能力,其框架的可重用性非常强,业务开发人员可以开发很少的代码来构建完整的领域业务系统(极端的例子表明,可以不用编写代码就能生成定制的业务系统)。这些框架绝对不是一开始就被构建出来的,而是在实现多个类似业务系统过程中,逐渐的演化形成的,这些可定制的框架为软件公司带来了滚滚的利润,也为开发人员带来了很大的成就感。对于普通的程序员,只要我们坚持用可重用的眼光思考问题,就能得到提升。

  首先,从小处看,我们应当保持代码的纯净,不能任何冗余的代码,冗余的即可重用。拷贝粘贴之余,只要我们坚持重构,在代码级别,我们能保持最大的重用性。更为重要的是,在保持了可重用性的同时,我们还集中了变化点,使得代码的维护变得更为容易。

  其次,组件级别(UI上称为构件),只要用相似的功能,我们都能精简,将业务上或者技术上相似的功能封装成可重用的组件,你就会更上一层楼。

  最高的境界就是框架层次上的,综合同领域内多个系统要面对的共同问题,构建一个可重用的框架,将会无数倍的降低我们构建类似系统的代价。

  我们应当树立“编程序即是编框架”的观念,从小处入手,胸怀天下,随时随地重构,追求代码,组件和系统的可重用性,在实现可重用性的同时,正交的隔离变化点,集中的控制变化点,自然的实现系统的应变能力和可扩展能力。对于目前的问题,我们将对这个组件级别的重用问题具体分析,找出一种有效的解决方法。现在的代码看上去虽然不错,但是因为所有的逻辑集中在ContentProvider和LabelProvider中,导致对需求的变化无法有效隔离,每一次的需求改动波及面很大,并且结构混乱,代码中充满了 if else 或 switch 这样的嵌套重复判断。分析一下前面提出的种种需求,我们都是可以将这些需求区分为行的行为和列的行为。因此,我们需要将MVC模式细化,对于我们的table而言,我们需要行控制器和列控制器,我们需要将类似的变化集中在某些地方,让这些细化的控制器各司其职。我们的目标是

  1 创建一个高度可重用的TreeTable构件使得我们批量的构建TreeTable的时候可以节省大量的工作;

  2 该构件能够精确控制行和列的显示以及行为;

  3 具有高度的可扩展性,便于增加新的功能而不破坏原有的结构。

  那么如何开始呢?你一定有过类似的经验,当你遇到无法解决的问题的时候,你会去研究一些开源的软件,开源软件的无私精神使你能够了解到世界上最顶级的代码,学习和研究这些代码会让你获益匪浅。所以让我们从Eclipse中的一些用户界面设计模式开始吧。

  2. 从Eclipse中的用户界面设计模式开始

  我们将在这一部分研究Eclipse的一些用户界面设计模式,从而了解到如何使用隔离关注的方法精确控制TreeTable 的行和列。

  实现列控制器的IField设计模式

  现在我们就要寻找一种SWT的设计模式,这个模式要能精确的控制Table中的每一列的行为。 没有问题,Eclipse的内部就使用这样一种设计模式,可以分散控制每个table的每一列的显示。研究Eclipse但源码和API文档,我们很快就发现,ProblemView这个view中引用了很多的IField的接口,当看到图3中IField接口的方法时,我们就了解到这个正是用来控制Table中的每一列的列控制器。

  图3: IField接口的方法

  IField接口的方法

  IField接口作为Table的列控制器,能够控制每列的列名,列头(Header)的icon,列头的tooltip,列头的tooltip的icon,每个 cell 的 Image 和 Text(getValue方法),并支持cell之间的比较,可以用于排序,我们将稍后详细的介绍该模式的运行原理。

  看上去这个是很不错的框架,遗憾的是在Eclipse中这种设计模式似乎并没有流行起来,从源码中我们就可以看见 LogView 就是完全按照我们第一部分的方法纯手工写就的。对于一个简单的 TreeTable,采用简单的方法做没有任何问题。问题在于,在应用系统中,你很难保证需求不会变更,功能不会膨胀,尤其在像在以表格展现为主的RCP应用中,TreeTable的编程 将成为你日常生活的一部分,此时创建一个高度灵活和可重用的TreeTable构件将显得异常重要。

  因此我们将使用这种模式来构建我们的TreeTable,我们只要在LabelProvider中调用到这些IField的方法,就能精确控制Table的列,那么,如何控制表格行的行为呢?

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章