这篇文章对COM做出来比较完整的解释,非常好。
COM是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种新的软件开发技术。在COM构架下,人们可以开发出各种各样功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。由此带来的好处是多方面的:可以将系统中的组件用新的替换掉,以便随时进行系统的升级和定制;可以在多个应用系统中重复利用同一个组件;可以方便的将应用系统扩展到网络环境下。
COM与语言,平台无关的特性使所有的程序员均可充分发挥自己的才智与专长编写组件模块。COM是开发软件组件的一种方法。组件实际上是一些小的二进制可执行程序,它们可以给应用程序,操作系统以及其他组件提供服务。开发自定义的COM组件就如同开发动态的,面向对象的API。多个COM对象可以连接起来形成应用程序或组件系统。并且组件可以在运行时刻,在不被重新链接或编译应用程序的情况下被卸下或替换掉。Microsoft的许多技术,如ActiveX, DirectX以及OLE等都是基于COM而建立起来的。并且Microsoft的开发人员也大量使用COM组件来定制他们的应用程序及操作系统。
COM所含的概念并不止是在Microsoft Windows操作系统下才有效。COM并不是一个大的API,它实际上象结构化编程及面向对象编程方法那样,也是一种编程方法。在任何一种操作系统中,开发人员均可以遵循“COM方法”。一个应用程序通常使由单个的二进制文件组成的。当编译器生成应用程序之后,在对下一个版本重新编译并发行新生成的版本之前,应用程序一般不会发生任何变化。操作系统,硬件及客户需求的改变都必须等到整个应用程序被重新生成。目前这种状况已经发生变化。开发人员开始将单个的应用程序分隔成单独多个独立的部分,也既组件。这种做法的好处是可以随着技术的不断发展而用新的组件取代以有的组件。此时的应用程序可以随新组件不断取代旧的组件而渐趋完善。而且利用已有的组件,用户还可以快速的建立全新的应用。传统的做法是将应用程序分割成文件,模块或类,然后将它们编译并链接成一个单模应用程序。它与组件建立应用程序的过程(称为组件构架)有很大的不同。一个组件同一个微型应用程序类似,即都是已经编译链接好并可以使用的二进制代码,应用程序就是由多个这样的组件打包而得到的。单模应用程序只有一个二进制代码模块。自定义组件可以在运行时刻同其他的组件连接起来以构成某个应用程序。在需要对应用程序进行修改或改进时,只需要将构成此应用程序的组件中的某个用新的版本替换掉即可。
组件对象模型是关于如何建立组件以及如何通过组件建立应用程序的一个规范,说明了如何可动态交替更新组件。组件架构的一个优点就是应用可以随时间的流逝而发展进化。除此之外,使用组件还有一些可以使对以有应用的升级更加方便和灵活的优点,如应用的定制,组件库以及分布式组件等。使用组件的种种优点直接来源于可以将它们动态的插入或卸出应用。为了实现这种功能,所有的组件必须满足两个条件:第一,组件必须动态链接;第二,它们必须隐藏(或封装)其内部实现细节。动态链接对于组件而言是一个至关重要的要求,而消息隐藏则是动态链接的一个必要条件。对于COM来讲,接口是一个包含一个函数指针数组的内存结构。每一个数组元素包含的是一个由组件所实现的函数地址。对于COM而言,接口就是此内存结构,其他东西;均是COM不关心的实现细节。在C++中,可以用抽象基类来实现COM接口。由于一个COM组件可以实现支持任意数目的接口,因此对于这样的组件,可以用抽象基类的多重继承来实现。用类来实现组件将比其他方法更为容易。对于客户来说,一个组件就是一个接口集。客户只能通过接口才能和COM组件打交道。从整体上讲,客户对于一个组件可以说是知之甚少的。通常情况下,客户甚至不必知道一个组件所提供的所有接口。客户同组件的交互是通过接口完成的。在客户查询组件其他的接口时,也是通过接口完成的。
所有的COM都要继承IUnknown。可以用Iunknown的接口指针来查询该组件的其他的接口,并且每个接口的vtbl中的前三个函数都是QueryInterface,AddRef和Release。这使得所有的COM接口都可以被当作成IUnknown接口来处理。由于所有的接口都支持QueryInterface,因此组件的任何一个接口都可以被客户用来获取它所支持的其他接口。在用QueryInterface将组件抽象成由多个相互独立的接口构成的集合后,还需要管理组件的生命期。这一点是通过对接口的引用计数实现的。客户并不能直接控制组件的生命期。当使用完一个接口而要用组件的另一个接口时,是不能将改组件释放的。对组件的释放可以由组件在客户使用完所有的组件之后自己完成。IUnknown的另外两个成员函数AddRef和Release的作用就是给客户提供一种让它指示何时处理完一个接口的手段。AddRef和Release实现的是一种名为引用技术的内存管理技术。当客户从组件获得一个接口时,此引用计数值将增1。当客户使用完某个接口时,组件的引用计数值将减1,当引用计数值为0时,组件可以将自己从内存中删除。AddRef和Release可以增加和减少这一计数值。将组件分成多个接口只是将单模应用分个成多个部分的第一步,组件需要被放入动态链接库(DLL)中。DLL是一个组件服务程序,或者说是发行组件的一种方式。组件实际上应看成是在DLL中实现的接口集。在客户获取某个组件接口指针之前,它必须先将相应的DLL装载到其进程空间中,并创建此组件。由于客户组件所需要的所有函数都可以通过某个接口指针而访问到,因此,可以在DLL中引出CreatInstance函数就可以使用户调用它。之后,可以装载DLL并调用其中的函数。此功能可由COM库函数CoCreateInstance来实现。CoCreateInstance创建组件的过程是:传给它一个CLSID,然后它创建相应的组件,并返回指向所请求的接口的指针。但CoCreateInstance没有给客户提供一种能控制组件创建过程的方法,缺乏一定的灵活性。事实上,常用类厂来创建组件。类厂就是一个带有能够创建其他组件的接口的组件。客户先创建类厂本身,然后再用一个接口(如IClassFactory)来创建所需的组件。然后还要用DllRegisterSever在Windows中注册这个组件。COM组件可以被复用,它支持“接口继承”。这种继承指的是一个类继承其基类的类型或接口。抽象基类是一种最纯粹的接口继承,并且正好也被用来实现COM接口。在COM中,我们可以用包容和聚合来对组件进行改造。包容是在接口级完成的。外部组件包含指向内部接口的指针。此时,外部组件仅仅是内部组件的一个客户而已,它将使用内部组件的接口来实现它自己的接口。外部组件也可以通过将调用转发给内部组件的方法来重新实现内部组件所支持的某个接口。并且外部组件还可以在内部组件代码的前后加上一些代码以对接口进行改造。聚合是包含的一种变化形式。当外部组件聚合了某个内部组件的一个接口时,它并没有象包容那样重新实现此接口并显式的将调用请求转发给内部组件。相反,外部组件直接把内部组件的接口指针返回给客户。使用这种方法,外部组件将无需重新实现并转发接口中的所有函数了。
包容和聚合为实现组件的复用提供了一种极具鲁棒性的机制。在组件构架下,客户于组件的实现完全隔离开了。
以上是关于COM的一些基础知识。遵循COM规范编写的组件将会极大的改变传统的软件生产方式,具有广阔的发展前景。这也将为软件工程学引入新的内容和方法。