在Eclipse RCP应用中利用扩展点机制解藕插件的依赖关系

Eclipse RCP 应用中利用扩展点机制解藕插件的依赖关系
在开发 Eclipse RCP 应用程序时,我们按照 Eclipse 插件的思路来组织和划分我们的程序模块,会使系统结构得到很大改善:比如 , 系统功能的灵活装配,系统的增量开发等。为了达到这种效果,我们要尽量减少插件之间的依赖关系。 Eclipse 平台中提供的扩展点机制可以用来实现这种目标。
一、业务场景
下面以一个具体的业务场景来说明:
比如,在我们的某个应用中,有 Workspace Document Job 三种业务功能,我们用三个 Eclipse 插件工程( WorkspacePlugin DocumentPlugin JobPlugin )分别来实现这些功能。
在三个插件中, WorkspaceView 管理所有的 Workspace 业务对象, DocumentView 管理所有的 Document 业务对象, JobView 管理所有的 Job 业务对象。
同时,这三种业务不是孤立的,它们之间是有交互的:打开 WorkspaceView 中的某个 Workspace DocumentView 会作相应改变:显示该 Workspace 下的所有 Document 。同样, JobView 也会根据 Workspace 的变化作相应的改变。
针对以上的业务场景,一种自然的做法是,在 WorkspacePlugin 中添加对另外两个插件的引用,直接在 WorkspaceView 中调用 DocumentView JobView 的相关方法。
但是这种做法导致了三个插件之间比较强的依赖关系,和我们的系统功能的灵活装配的目标有所差距。下面我们利用 Eclipse 扩展点机制来解决这种问题。
二、定义扩展点
不难看出,上述场景是一个典型的 Observer 模式的应用: WorkspaceView 是交互的发起者,而 DocumentView JobView 是交互的监听者。
为了简便起见,在这里不再创建新的插件来容纳我们的接口和扩展点,我们在 WorkspacePlugin 定义一个 Workspace 监听器接口: IWorkspaceListener
public interface IWorkspaceListener {
   void workspaceOpened(Workspace ws);
   void workspaceClosed(Workspace ws);
}
接下来,我们针对 IWorkspaceListener 接口定义 Workspace 监听器扩展点: workspacelisteners
// 注:我的开发环境是 Eclipse3.2+ 中文语言包 , 如果是其他版本和语言,界面文字可能和下面的描述有所出入。
Eclipse IDE 中,打开 WorkspacePlugin 下的 plugin.xml (用插件清单编辑器的方式打开),切换到“扩展点” Tab 页,新建一个扩展点:
在“扩展点标识”一栏输入我们上面确定的扩展点名称: workspacelisteners ,在“扩展点名称”一栏输入一个友好的用于显示的名称,比如: workspace listeners 。确定后,将会在工程的 schema 目录下生成一个 workspacelisteners.exsd XML 文件,同时会打开扩展点模式编辑器。
在扩展点模式编辑器中,我们输入一些该扩展点的其他信息,然后切换到“定义” Tab 页:
新建一个名称为“ listener ”的元素,然后在“ listener ”下新建一个名为“ class ”的属性节点。
选中“ class ”节点,在右边的面板上编辑它的详细信息,在第三栏“使用”,默认是“ optional ”,我们这里改为“ required ”。这表明其他插件在使用本扩展点时,“ class ”属性必须指定。
然后,我们在默认的“ extension ”元素上,新建一个“序列” (sequence) 。在“序列”点击右键,新建“引用”,将上面建立的“ listener ”元素加入序列。
至此,一个简单的扩展点定义完毕。
下图是在扩展点模式编辑器中看到的扩展点的定义结构的截图:
 
三、使用扩展点
上面的扩展点定义完毕, WorkspacePlugin 更新后,我们分别在 DocumentPlugin JobPlugin 的插件依赖项中加上 WorkspacePlugin ,这样在这两个插件中就可以使用 workspacelisteners 了。
使用 workspacelisteners 扩展点和使用 Eclipse RCP 中提供的其他扩展点没有任何区别。下面以 DocumentPlugin 为例简单说明。
根据业务场景的描述, DocumentView 应该实现 IWorkspaceListener 接口:
public class DocumentView extends ViewPart implements IWorkspaceListener{
   public void workspaceOpened(Workspace ws){
    //todo...
    // 实现 workspace 打开后的相关更新
   }
   void workspaceClosed(Workspace ws){
    //todo...
    // 实现 workspace 关闭后的相关更新
   }
}
接下来,我们在 plugin.xml 中声明使用 workspacelisteners 扩展点:
打开 plugin.xml 文件,切换到“扩展” Tab 页,添加扩展点,找到 workspacelisteners ,确定。在“所有扩展”列表中就会看到“ workspacelisteners ”节点,右键点击“ workspacelisteners ”节点,新建一个扩展元素,选择我们前面定义的“ listener ”。
然后设置 listener 的“ class ”属性为 DocumentView 类的完整类名 ( 包括 package) ,这里是“ document.DocumentView ”。
至此, DocumentPlugin 中使用 workspacelisteners 的相关工作已经完毕。在 JobPlugin 使用和上述基本类似,这里不再赘述。
四、加载扩展点
在前面的描述中,我们在 WorkspacePlugin 中定义了 workspacelisteners 扩展点,在 DocumentPlugin JobPlugin 中使用了 workspacelisteners 扩展。下面我们需要在 WorkspacePlugin 加载所有的扩展,以便 WorkspaceView 变化时向这些扩展发出通知。
我们在 WorkspaceView 定义一个方法来加载扩展。
public class WorkspaceView extends ViewPart {
      
private List<IWorkspaceListener> listeners= new ArrayList<IWorkspaceListener>();
    private Workspace ws; // 打开的 Workspace
    public void loadWorkspaceListeners(){
        IExtensionRegistry registry = Platform.getExtensionRegistry();
        // 注:这里传入的扩展点的名称必须是全名,包括 plugin 的名称。
              IExtensionPoint point = registry.getExtensionPoint( "workspace.workspacelisteners" );
              IExtension[] extensions = point.getExtensions();
              for ( int i=0;i<extensions.length;i++){
                     IConfigurationElement[] elements = extensions[i].getConfigurationElements();
                     for ( int j=0;j<elements.length;j++){
                            try {
                                   Object listener=elements[j].createExecutableExtension( "class" );
                                   if (listener instanceof IWorkspaceListener)
                                          listeners.add((IWorkspaceListener)listener);
                            }
                            catch (CoreException e){
                                   //....todo
                            }
                     }
              }
    }
   
    // 当界面操作打开 Workspace , 调用此方法通知所有 IWorkspaceListener
    public void notifyWorkspaceOpened(){
        Iterator<IWorkspaceListener> it=listeners.iterator();
        while (it.hasNext())
            it.next().workspaceOpened(ws);
    }
   
    // 当界面操作关闭 Workspace , 调用此方法通知所有 IWorkspaceListener
    public void notifyWorkspaceClosed(){
        Iterator<IWorkspaceListener> it=listeners.iterator();
        while (it.hasNext())
            it.next().workspaceClosed(ws);
    }
}
参考资料:
Contributing to Eclipse 中文版》
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值