Eclipse 的 Java 开发环境的重构(refactor)能力是它提供的最有用的特性之一。本文将向您介绍创建您自己的重构(作为 Eclipse 的自然扩展)步骤。本文所提供的解决方案的许多部分摘自最近出版的 The Java Developer's Guide to Eclipse 一书。
由于 Eclipse 具有功能强大的 Java 开发环境,这使它获得了人们的一致好评。这个 Java 开发环境(再加上团队环境和其它基础功能)使 Eclipse 成为引人注目的集成开发环境,对 Java 开发人员来说,这是个好消息。而且,Eclipse 还是一个开放源码项目。但真正使人们对 Eclipse 感到兴奋的是它提供了扩展的可能性。
许多基于 Eclipse 的商用产品都显示出这种提供集成产品的方法的实际意义。例如,IBM WebSphere Application Developer 和 Rational XDE 就说明了 Eclipse 已具有的影响。这些产品和其它基于 Eclipse 的产品降低了用户的“学习曲线”,因为它们具有类似的用户界面。当然,对于大型软件公司来说,这颇有价值,但是对于小公司或个人有什么用吗?
这正是 Eclipse 扩展性能力让人感兴趣的地方。不仅那些拥有大型开发组织的公司可以用它进行集成,任何愿意花些时间学习几个 Eclipse 框架的人也都可以利用这一能力。“哦不,”您可能在想,“别再提什么框架;我没时间学习更多框架。”不必担心;这学起来很快而且相当容易。在您的另一丝疑虑在头脑中开始形成之前,先声明一点,本文绝不是对 Eclipse 进行毫无价值的“hello world”式扩展。请放心,在如何增强 Eclipse 的 Java 开发环境的生产性使用方面,您将看到实际的价值以及一个清晰演示。您甚至还可能有点惊奇地发现:要完成某些相当令人惊异的事情,只要几十行代码就可以了。
本文将向您展示什么是可能的,从哪里开始,并将向您提供开始时需要什么的可靠评价。尽管扩展 Eclipse 是一个高级主题,但是您只要先了解如何使用 Eclipse 的 Java 开发环境就可以了。
自己轻松重构成员可视性 最初在编写代码时,我没有过多地担心将方法可视性归为 default(包)、private、public 还是 protected。在创建方法时,我使它们都为 public。只有当我最后定下了包的组织结构并完成了对方法的重构 - 不管是通过从现有代码抽取出新方法、在层次结构中上移或下移方法还是将方法整个地移至其它类中 - 我才会重新检查方法的可视性。我认为,在我知道最终类的模样并实际使用过代码之前,我不想声明我的“客户们”可能需要什么。换句话说,在共享新框架之前,必须确定什么是实现细节,什么是必需的,这样别人才能够扩展它。
如果只需在 Outline 视图、Hierarchy 视图或任何您查看方法的地方选择方法 - 然后通过单击菜单选项,就可以将一个或多个方法设置成所期望的可视性 - 那么这会非常方便。诚然,我习惯了在我使用 VisualAge for Smalltalk 那段日子里学到的这一功能。图 1 显示了对 Eclipse 的 Java 开发环境中 Java 编辑器的 Outline 视图上下文的扩展。
图 1. 对方法的上下文菜单进行的扩展 从用户的角度而言,这很巧妙,因为这是引入用户界面的很自然的方法。没有任何暗示说这些新的菜单选项不属于 Eclipse 最初的 Java 开发工具(Java Development Tool,JDT)。事实上,那就是菜单级联使用“soln”前缀的原因 - 这样您就可以分辨出它是一个扩展!而且,开发人员不必记住只有在特定视图或编辑器中才可以使用这些选项,因为只要方法显示在哪里,它们就可以在哪里显示。
简述“Hello World” “嘿,等一下,您承诺过不会有‘Hello, World’的!”是的,但在我们开始讨论真正有趣的事情之前,确实需要先来了解一下 Eclipse 的基础。所以,如果您从未编写过自己的 Eclipse 扩展,那么请和我一起快速了解一下 Eclipse 的体系结构和插件开发环境。否则,请跳至下一节。继续这次“旅行”!
本质上,Eclipse 是一组松散绑定但互相连接的代码块。如果搞清楚这些代码块如何被“发现”,以及它们之间怎样相互发现和扩展,就能了解 Eclipse 体系结构的基本原理。
图 2. Eclipse 平台体系结构 这些功能单元称为插件。Eclipse 平台运行时(参见图 2)负责在名为 plugin.xml 的文件中查找这些插件的声明(称为插件清单),每个 plugin.xml 文件都在各插件的子目录中,这些子目录位于 Eclipse 的安装目录下名为 plugins 的公共目录(具体而言,就是 \eclipse\plugins)。根据这些文件,Eclipse 平台运行时就在启动时在内存中构建一个全局注册表,称为插件注册表,根据这个注册表,给定的插件就可以在运行时确定其它哪些插件希望扩展它。希望被其它插件扩展的插件将声明一个扩展点。这是插件的某种“电源板”,通过对插件声明扩展,其它插件就可以利用这个插件。
回到我们的示例,那么任务就是通过查找满足我们需要的相应扩展点来决定从哪里“插入” Eclipse。幸运的是,一旦使用 Eclipse 一段时间后,您就会知道有数量惊人的东西可以使用,尽管可能您还没有实际使用过。这是因为您在 Eclipse 用户界面所看到的与由构成 Eclipse 插件的类所建的模型通常几乎是一一对应的。图 3 使这一点更为清晰:
图 3. 视图及其模型 这里我们看到一系列普通的用户界面,右侧的是最广为人知的用户界面 - 命令提示符(Command Prompt)窗口,在其中用 dir 命令显示文件系统内容,然后是左边专门化程度较高的视图 - JDT 的 Package Explorer。从用户界面的角度来看,所有这些视图都将同一“模型”(也就是一些文件)的表示可视化。作为 Eclipse 用户,我们很自然地会希望这两个 Eclipse 视图同时向我们提供查看同一事物的不同方法:Navigator 展示了部分操作系统文件的专门化视图(Eclipse 的工作空间),而 Package Explorer 向我们展示了同样的一些文件,这些文件是用对 Java 程序员而言更自然更高效的方法组织和表示的。
通过了解 Eclipse 用户界面如何反映其底层模型,以及 Eclipse 模型如何成为相互构建的基础,这向我们提供了该如何找到“插入”我们扩展的最佳位置的重要线索。显示在视图下面的 Eclipse 接口名称 IFile 和 ICompilationUnit 就是我们可以预期从构成 Eclipse 的模型中获得的两个接口示例。由于它们通常对应于用户界面中显示的控件项,所以您已经对通过编程获得的效果有一个直观的感受。
这是我们“旅行”的第 I 部分。在第 II 部分中,我们将讨论开发解决方案。我们不打算提供这个解决方案并逐一解释,探索其中的一些奥秘,这不是更有趣吗?让我们首先讨论与以下这个问题相关的一些问题:使用我们自己的方法可视性重构能力来扩展 JDT。
把问题问在点子上比知道答案更重要
我们先探讨一些常规问题:
在用户界面中,如何显示扩展,以及显示在何处?
通常如何扩展用户界面?
对用户界面的扩展如何知道类似于“选择”这样的基本事件?
我们对基本 Eclipse 领域有了很好的了解之后,将转向一些特定于 JDT 的问题:
如何扩展 JDT 的特定元素的用户界面(象 Outline 视图中显示的成员)?扩展视图还是它们的底层模型?
Package Explorer 中显示的元素和其它视图(如 Outline 视图)中显示的相同元素之间有什么关系?我们的扩展需要知道它们之间的任何区别吗?
如何通过编程更改 JDT 模型?
怎样分析 Java 源代码以进行修改?