hangke的专栏

个人经验有限,大家共享无穷

在Eclipse RCP应用中利用扩展点机制解藕插件的依赖关系
Eclipse RCP应用中利用扩展点机制解藕插件的依赖关系
在开发Eclipse RCP应用程序时,我们按照Eclipse插件的思路来组织和划分我们的程序模块,会使系统结构得到很大改善:比如,系统功能的灵活装配,系统的增量开发等。为了达到这种效果,我们要尽量减少插件之间的依赖关系。Eclipse平台中提供的扩展点机制可以用来实现这种目标。
一、业务场景
下面以一个具体的业务场景来说明:
比如,在我们的某个应用中,有WorkspaceDocumentJob三种业务功能,我们用三个Eclipse插件工程(WorkspacePluginDocumentPluginJobPlugin)分别来实现这些功能。
在三个插件中,WorkspaceView管理所有的Workspace业务对象,DocumentView管理所有的Document业务对象,JobView管理所有的Job业务对象。
同时,这三种业务不是孤立的,它们之间是有交互的:打开WorkspaceView中的某个WorkspaceDocumentView会作相应改变:显示该Workspace下的所有Document。同样,JobView也会根据Workspace的变化作相应的改变。
针对以上的业务场景,一种自然的做法是,在WorkspacePlugin中添加对另外两个插件的引用,直接在WorkspaceView中调用DocumentViewJobView的相关方法。
但是这种做法导致了三个插件之间比较强的依赖关系,和我们的系统功能的灵活装配的目标有所差距。下面我们利用Eclipse扩展点机制来解决这种问题。
二、定义扩展点
不难看出,上述场景是一个典型的Observer模式的应用:WorkspaceView是交互的发起者,而DocumentViewJobView是交互的监听者。
为了简便起见,在这里不再创建新的插件来容纳我们的接口和扩展点,我们在WorkspacePlugin定义一个Workspace监听器接口:IWorkspaceListener
publicinterface 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.exsdXML文件,同时会打开扩展点模式编辑器。
在扩展点模式编辑器中,我们输入一些该扩展点的其他信息,然后切换到“定义”Tab页:
新建一个名称为“listener”的元素,然后在“listener”下新建一个名为“class”的属性节点。
选中“class”节点,在右边的面板上编辑它的详细信息,在第三栏“使用”,默认是“optional”,我们这里改为“required”。这表明其他插件在使用本扩展点时,“class”属性必须指定。
然后,我们在默认的“extension”元素上,新建一个“序列”(sequence)。在“序列”点击右键,新建“引用”,将上面建立的“listener”元素加入序列。
至此,一个简单的扩展点定义完毕。
下图是在扩展点模式编辑器中看到的扩展点的定义结构的截图:
 
三、使用扩展点
上面的扩展点定义完毕,WorkspacePlugin更新后,我们分别在DocumentPluginJobPlugin的插件依赖项中加上WorkspacePlugin,这样在这两个插件中就可以使用workspacelisteners了。
使用workspacelisteners扩展点和使用Eclipse RCP中提供的其他扩展点没有任何区别。下面以DocumentPlugin为例简单说明。
根据业务场景的描述,DocumentView应该实现IWorkspaceListener接口:
publicclass DocumentView extends ViewPart implements IWorkspaceListener{
   publicvoid 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扩展点,在DocumentPluginJobPlugin中使用了workspacelisteners扩展。下面我们需要在WorkspacePlugin加载所有的扩展,以便WorkspaceView变化时向这些扩展发出通知。
我们在WorkspaceView定义一个方法来加载扩展。
publicclass WorkspaceView extends ViewPart {
      
private List<IWorkspaceListener> listeners=new ArrayList<IWorkspaceListener>();
    private Workspace ws;//打开的Workspace
    publicvoid 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
    publicvoid notifyWorkspaceOpened(){
        Iterator<IWorkspaceListener> it=listeners.iterator();
        while(it.hasNext())
            it.next().workspaceOpened(ws);
    }
   
    //当界面操作关闭Workspace,调用此方法通知所有IWorkspaceListener
    publicvoid notifyWorkspaceClosed(){
        Iterator<IWorkspaceListener> it=listeners.iterator();
        while(it.hasNext())
            it.next().workspaceClosed(ws);
    }
}
参考资料:
Contributing to Eclipse 中文版》
 
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

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

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭