您的位置:首页 > 编程语言 > Java开发

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

2007-01-29 13:43 786 查看
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 中文版》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: