面向对象系统的3个最基本特征是封装性、多态性、重用性。
所谓的重用性是指,当一个程序单元能够对其他的程序单元提供功能服务是,尽可能的重用原先程序单元的代码,既可以在源代码一级重用,也可以在执行代码一级重用。C++语言的可重用性位于源代码一级,一个类可以继承于另一个类,从而把父类的功能重用。但是对于COM组件有所不同。COM重用性指的是一个COM对象如何重用已有的COM对象的功能,而不是重复实现老的功能服务,按照COM标准,实现这种重用性有两种途径:包容和聚合。
包容和聚合
包容和聚合的基本思路一致,实现方法不同。
包容:假设已经实现一个COM对象A,它实现接口ISomeInterface,不就之后,考虑到新的需要,实现一个新的COM对象B,它既要实现接口ISomeInterface,也要实现接口IOtherInterface,而且,ISomeInterface接口提供的服务于对象A的接口所提供的功能基本一致,于是,在实现B对象的过程中可以重用对象A的功能,最简单的办法就是在实现对象B的接口ISomeInterface时调用对象A相应的成员函数,对于对象A来说,它只是当做一个普通的COM对象。而对于B来说,虽然它本身是一个COM对象,但是它也是对象A的客户,因为它调用A的服务。对象B不在重复实现对象A已经实现的功能,而是调用对象A的服务来提供对外的功能服务,对于对象B的客户来说,它根本不知道A对象的存在。这样的情形,我们成为对象B包容对象A。
聚合:假定我们要实现一个对象B,它支持两个接口ISomeInterface和IOtherInterface,同时对象B所提供的ISomeInterface功能在另一个对象A中已经实现,而且不需要修改就可以满足B的要求,如果采用对象包容模型,则B需要实现两个接口,并且在接口ISomeInterface的成员函数中调用对象A的相应函数,如果采用聚合来实现对象B,对象B本身不实现接口ISomeInterface,它只实现IOtherInterface接口,但它也能提供接口ISomeInterface的功能,对象B的客户请求接口ISomeInterface时,对象B吧对象A的ISomeInterface接口指针暴露给客户程序,因此,客户程序调用ISomeInterface时直接与对象A进行交互,但客户并没有感觉到在与对象A进行交互
在聚合模型中,虽然对象A直接向对象B的客户提供服务,但它是生存周期受B控制。实现聚合的关键在与对象B的QueryInterface成员函数,当客户程向对象B请求ISomeInterface接口时,对象B的QueryInterface函数把对象A的ISomeInterface接口指针放到输出函数中,客户程序就获得了对象A的ISomeInterface接口指针,可以直接调用接口成员函数了
但是,并没有这么简单,当客户程序通过ISomeInterface;:QueryInterface函数又请求其他的接口指针时,因为对象A并不知道对象B实现了什么样的接口,而根据COM规范,客户程序从对象B的任一接口可以获得其他任何接口的指针,而且在正常情况下,客户程序调用对象A的ISomeInterface::QueryInterface函数请求IUnknown接口指针获得的是对象A的IUnknown接口指针,而客户程序调用对象B的IOtherInterface::QueryInterface函数请求IUnknown接口指针获得是对象B的IUnknown接口指针,而COM规范要求,对象的IUnknown接口指针必须唯一,因此,为了是聚合能顺利实现,对象A也必须能够实现在被聚合情况下进行特殊的处理,尤其是接口的QueryInterface成员函数,在被聚合的情况下,当客户要求它所不支持的接口或者请求IUnknown接口时,它必须把控制交给外部对象,有外部对象决定客户程序的请求结果。