组件的创建过程
在《设计模式》一书中,作者把创建模式放在了该书的最前面,我想这一定是经过深思熟虑之后才决定的。试想,如果没有创建模式,接口的使用者必须要知道接口的具体实现,才能创建并使用它,那么接口的实现可能就要遍布整个系统了。如果是这样,那还能算是分离了接口与实现吗,还能算是针对接口编程吗?答案是否定的,所以创建模式尽管很简单,但它却是针对接口编程必要的手段。
而在组件对象模型(COM) 中大量使用了创建模式中的工厂模式。在XPCOM中,几乎所有组件都是通过工厂(Factory)来创建的。一个组件可以实现多个接口,一个 Factory可以创建多个接口,所以通常一个组件只要实现一个Factory接口就够了,而不必为每个接口实现一个Factory。
MSCOM的Factory接口叫作IClassFactory。记得当时有人说,这个名字取得不好。原因是IClassFactory生产的是对象而不是类,所以正确的名字应该叫IObjectFactory。呵,这倒是很有道理的。
在介绍mozilla的组件创建过程之前,让我们先回忆一下MSCOM组件的创建过程,这对理解XPCOM组件的创建过程也是有帮助的。
对于以动态库形式提供的MSCOM组件,必须export出下面这些函数:
1. DllGetClassObject 用来查询组件内的接口。
2. DllRegisterServer 向系统注册组件。
3. DllUnregisterServer 向系统注销组件。
4. DllCanUnloadNow 判断是否可以安全卸载组件。
为了让客户可以使用自己,组件首先要把自己注册到系统中去。注册过程实际上就是向注册表中写入一些信息,让客户可以找到组件对应的动态库。然后客户通过系统API (如CoCreateInstance)创建来组件的实例,而CoCreateInstance等API先从注册表找到该组件的动态库,再调用动态库 DllGetClassObject函数查询到IClassFactory接口,最后通过IClassFactory去创建组件的实例。
在mozilla中,XPCOM组件的创建与MSCOM组件的创建类似。这里的模块(Module)是一个物理实体(通常是动态库或JS包),一个模块(Module)内可以封装多个组件,而每个组件内又可以实现多个接口。
模块(Module)必须对外export出NSGetModule函数,该函数的功能是用来得到nsIModule接口的。nsIModule接口的主要函数如下:
1. GetClassObject用来查询组件内的接口。对应MSCOM的DllGetClassObject函数。
2. RegisterSelf向系统注册组件。对应MSCOM的DllRegisterServer函数。
3. UnregisterSelf向系统注销组件。对应MSCOM的DllUnregisterServer函数。
4. CanUnload判断是否可以安全卸载组件。对应MSCOM的DllCanUnloadNow函数。
mozilla 实现了一套宏,一个通用的Module(nsGenericModule)和一个通用的Factory(nsGenericFactory),在它们的帮助下,模块只要实现一个nsModuleComponentInfo结构就行了,这大大简化了开发的繁杂度。nsModuleComponentInfo 的成员仍然比较多,幸好通常只要提供mDescription、mCID、mContractID和mConstructor几个成员就行了。
nsGenericFactory 实现了nsIFactory接口,它只是对nsModuleComponentInfo的一个包装。NsIFactory的功能和MSCOM中的IClassFactory差不多,它需要提供下列接口函数:
1. CreateInstance 创建指定接口的实例。
2. LockFactory 加锁/解锁工厂。
有了以上的背景知识,mozilla的组件创建过程就不难理解了:
1. mozilla调用NSGetModule获取IModule接口。(初始化时)
2. mozilla调用IModule接口的RegisterSelf函数,向组件管理器注册组件。(初始化时)
3. 通过组件管理器查找组件的nsIFactory接口,然后通过组件的nsIFactory接口创建组件。
这样一来,组件的使用者和实现者之间耦合就降到最低了,两者独立变化而互不影响。
值得注意的是,在XPCOM中,组件的创建有两种方式:
1. 创建实例(CreateInstance)。这是普通的创建方式,每次都调用Factory::CreateInstance来创建新的实例。
2. 获取服务(GetService)。服务(Service)一词容易让人误解(我开始以为是跨进程的调用呢),其实这里的服务就是一个单件,也就是说该组件只有一个实例存在。获取服务时,组件管理器发现如果先前已经创建过该组件的实例,就直接返回先前的实例,否则调用 Factory::CreateInstance创建组件的实例,并保存该实例的引用以备后面再使用。
无论是以创建实例还是以获取服务的方式创建,对组件本身的实现没有太大的影响。只是如果按获取服务的方式创建,而且该服务可能在多线程环境下使用,那么组件要自己实现加锁保护。
分享到:
相关推荐
VC代码 mozilla-19980728.tar (实用代码源)VC代码 mozilla-19980728.tar (实用代码源)VC代码 mozilla-19980728.tar (实用代码源)VC代码 mozilla-19980728.tar (实用代码源)VC代码 mozilla-19980728.tar (实用代码源)...
资源来自pypi官网。 资源全名:mozilla-django-oidc-0.1.9.tar.gz
mozilla-win32-1.3-installer.exe用于cygwin搭建环境。
离线安装包,亲测可用
org.mozilla.javascript-1.7.2.jar资源包
前端开源库-mozilla-toolkit-versioningMozilla工具包版本控制,Mozilla工具包版本格式的解析器
aframe-sdf-component 一个Mozilla A-Frame组件,用于加载模型作为组件当前状态目前,这还处于非常初步的阶段。 虽然最终目标是最终增加对SDF实现的所有细节的支持,但是项目进行的方式是通过在及其增加对所有模型的...
离线安装包,亲测可用
官方离线安装包,亲测可用
离线安装包,亲测可用
mozilla-opennews 是支持 Mozilla Opennews 项目的静态网站。Knight-Mozilla OpenNews 是一个构建能让新闻事业茁壮生长的生态环境。它旨在生产出能解决新闻界存在的问题的下一代 Web 解决方案。它能支持社区的开发者...
离线安装包,亲测可用
java javascript jsp 等调试工具
mozilla-plugin-vlc_0.8.6.release-0ubuntu4.2_amd64.deb
前端开源库-mozilla-version-comparatorMozilla版本比较器,Mozilla版本比较器是Mozilla软件中使用的版本控制策略的JavaScript实现。请参阅https://developer.mozilla.org/en-us/docs/toolkit_version_格式以获取...
org.mozilla.javascript
资源来自pypi官网。 资源全名:mozilla-django-oidc-1.2.4.tar.gz
mozilla-source-1.7.5.tar.bz2.rar 安装openoffice的编译需要的一个资源。
mozilla firefox 开发者文档,把所有的网页下载下来的打包。有的朋友上网不方便,直接下载阅读。能上网的直接上网看了。
MyCurses-Mozilla-源码.rar