作为一个桌面应用的开发者,向
RCP
致敬的理由会是
RCP
提供了丰富的界面控件,使得基于
Java
开发桌面应用也变得容易了很多,尽管仍然不能和基于
VB
、
Delphi
去相比;对于我而言,尽管使用
RCP
也是为了开发桌面应用,但
RCP
给我带来的更多的感觉是在它充分发挥插件化系统的优势方面,
RCP
可以视为基于
OSGi
构建插件化系统的最佳实践的指导,从
RCP
的设计中,可以学习到如何让应用做到模块化、让应用做到动态化,甚至还可以学习到象如何自动生成界面这样的细节设计思想,尽管我自己基于
OSGi
做应用型的产品也做了一段时间了,但自己仍然一直感觉到在发挥插件化系统的优势方面还有不小差距,
RCP
可以看做是基于
OSGi
做插件化应用系统的最佳实践,其中的不少设计方法甚至都可以整理成为基于
OSGi
做插件化应用系统的设计模式,让我们进入
RCP
之旅,揭开面纱,一探其本质吧,相信大家在了解了
RCP
的设计思想,看过其代码后,不得不对
RCP
表示崇高的敬意,大师之作,不同凡响。
致敬理由一:即插即用
/
即删即无的设计
/
实现指导
在构建插件化的应用系统的时候,我们通常希望做到以下三点:
1.
通过增加插件来动态扩展系统功能,包括功能的入口等,最重要的就是不要因为增加的新的插件,而导致对原插件的修改,做到即插即用,
OSGi
本身提供了基于插件动态扩展系统功能的支持,但是否可以真的做到即插即用,是否可以不导致对原插件的修改,这个还是要看设计者的功力;
2.
通过删除插件来动态移除系统功能,包括功能的入口等,最重要的就是要让插件的卸载不影响到系统的运行,这个和
1
里面所说的情况也是一样的,
OSGi
是可以支持这样的要求,但应用系统是否能做到还是看设计者的功力;
3.
通过增加或更新插件来动态改变系统行为。
RCP
呢,通过基于
OSGi
来保证其插件化以及动态化可实现的情况下,还定义了扩展点的机制,而正是因为扩展点的机制,使得
RCP
在设计角度能够更好的达到了我们构建插件化应用系统的前两个目标,同时
RCP
通过其对桌面应用支撑的设计为我们展示了扩展点的最佳实践方法,将界面按照对象的思想进行划分,在划分的过程中根据职责形成插件,暴露出扩展点,最后形成了象树一样的结构体系,如图所示:
图表
1
RCP
结构示意图
这种设计方法最佳的一个地方就在于充分的做到了真正的即插即用、即删即无的情况,典型的例子就是在
RCP
中可以通过扩展实现
Perspective
,将这个插件安装上后就可以在
RCP
中看到这个
Perspective
,删除这个插件后
RCP
中自然就看不到这个
Perspective
了。
从
RCP
的结构体系上,可以看出
RCP
在基于扩展点的设计思想上是怎么去设计的,它的设计思路采取的就是从顶至下、按照职责进行划分、形成插件的方法,插件中需要支持动态扩展的部分则做成扩展点,从而形成一个非常容易扩展的开发平台。
这对于
B/S
系统的设计有什么指导的地方呢?至少在我自己目前的基于
OSGi
的产品的
B/S
部分上,我承认并没有做到真正的即插即用、即删即无,在安装一个插件后其菜单的链接需要手工的加上、在删除一个插件后其菜单的链接也需要手工的删除,而模块内的按钮呀等等元素,也是同样如此,并没有做到说增加一个插件,模块内的按钮就可以自动增加这样的情况,而这呢,其实一定程度上就削弱了插件化带来的好处,
:)
,当然,这里的例子说的有些极端了,并不是每个按钮、每个界面都要追求完全的插件化的,但这种设计思想是非常有用的,系统中需要支持插件化的地方多着呢,在这样的场景下
RCP
就提供了实现的设计思想和参考了,而且这种设计思想还可以延伸到后台模块部分,来看看参考
RCP
使用扩展点的方式来改造下
B/S
系统的设计方法。
先来看看界面部分,界面怎么样去设计,使其能够支撑插件的即插即用、即删即无这也是非常关键的,这个部分几乎是完全可以参考
RCP
的设计,但要考虑
B/S
系统的特殊性,例如
B/S
系统在界面展现上采用
Html
这样的方式显然更为适合,在这样的设计的情况下,
B/S
系统界面中的公用菜单、按钮等部分就可以由各模块的插件扩展来构成了,而当插件卸载时,这些公用菜单、按钮中的东西自然就没有了,而对于模块内的元素也需要考虑采取类似的设计,把握住设计原则就行了,需要支持动态扩展的部分就做成扩展点,
Eclipse
对于这种扩展称为贡献,这个名词取的实在是太好了。
再来看看后台模块部分,后台模块部分之前一直说的在
OSGi
中采用
Hibernate
比较的麻烦,只能采用将所有模块的
po
都放入同一个
Bundle
的折衷方案,而其实采用类似扩展点的设计方法的话,就可以实现各
PO
放入各模块自己的
Bundle
中了,这个我会通过
demo
的方式来进行说明,其实这样的方法同样可以衍生到
webwork
那些中去,让这些传统的开源的东西都能够支撑插件化。
从这个方面来看,
RCP
的扩展点的设计思想为实现即插即用、即删即无提供了可行的设计方式,同时它的实现方法更是为我们如何采用扩展点机制来实现这个提供了指导,在这里呢,也要纠正了下自己以前对于
RCP
的扩展点的看法,尽管扩展点的实现确实可以基于
OSGi
的
service
的方式来实现,但在很多场景下确实不如
RCP
本身的扩展点机制好用,例如在帮助视图中,就是一个典型的场景,因为那只是替换了一个帮助的文本信息和图片而已,根本用不着去写类来实现,这点上来说扩展点的机制还是非常好用的,
Equinox
中现在也有扩展点这个插件,还是比较爽的,
J
。
即插即用、即删即无的支持使得系统可以很好的以插件的方式来进行组装,做系统的时候就象在种树,先把系统的根撒下,让根长出主干,在主干上培育出枝叶,枝叶上结点果实,整颗树就这么养成了,当不需要了某个果实的时候,把它摘下来吃了,当不需要了某颗枝叶的时候,把那颗枝叶砍了,而这都不会影响到主干,当希望树上形成别的果实的时候,甚至都可以接上个不同的枝叶,让它长出不一样的果实,比普通树强多了,改名成高科技树算了,
J
。
致敬理由二:动态的选择插件来形成功能
/
界面
扩展插件是一个需要支持的方面,但怎么样根据时机来选择合适的插件呢,这个问题显然就是在支持扩展插件后的一个更重要的问题了,为什么这么说呢,一个典型的场景如下:
系统中几个插件都扩展提供了右键弹出的菜单,在运行的过程中,肯定是希望插件只弹出自己的那部分扩展的菜单,而不会希望什么菜单都出现,这呢,就需要动态的去选择插件来形成菜单,在
RCP
中这块的设计采用的是在扩展点中增加标识的方式,这样的话在获取扩展点实现的时候就可以通过获取相应的标识来进行过滤,这个功能呢,和
OSGi
中支持
service
的过滤是一样的,虽然这不属于
RCP
的创意,但这也是一个实践的不错的指导。
在形成界面方面
RCP
采用了同样的方法,例如在一个属性窗口中,系统可以自动的根据其中字段扩展点的实现加上标识的过滤来组装出不同的界面,把这个设计思想引入到
B/S
界面的自动生成上是不是也是个不错的思想呢,
J
。
目前对
RCP
了解还不是非常的多,设计角度而言最让我心动的就是上面的两个理由,但其实
RCP
还提供了非常多的细节的可参考的东西,那都是非常值得学习的,
RCP
的代码非常的值得一读,相信大家在读了后都会觉得不亚于一顿大餐美食,希望大家多多挖掘,共同分享这顿难得的美食。