从C++到COM,学习笔记(5)


包容和聚合
 
一. COM组件的升级/扩展需求
在一开始的分析中,已经假设了COM模型中目标就是单个组件的重用性达到最佳。但是,单个组件发布后,功能就已经固定下来了。随着用户的需求不断增加,很可能现有组件将无法完成好用户的所有需求,因此必须对现有组件进行升级。
然而,对既有组件的升级其实并不是一件简单的事情。首先最初的编写者和后来的升级者不一定是同一个人,他们擅长的编程语言也不一定一样,而且更糟糕的是原有的源代码可能无法看到或者写的非常晦涩。如果做过程序维护的话就应该理解,要想看明白别人的程序是一件多么痛苦的事情。
因此,对COM而言,希望做到的就是,尽可能多的利用原来的二进制代码,增加新的功能。也因此,提出了2种实现的方法。但是,不管怎么实现,最初的重用方针就决定了在升级版的COM对象CExt中一定要有一个原有版本的COM对象COri。CExt创建的时候COri也创建,CExt卸载的时候COri也卸载。花招在于CExt如何使用COri的接口,换句话说,当有一个CExt的接口后,怎样才能使用COri的接口呢?
 
二. 包容
包容是一种很自然的思想。就是在CExt中逐一定义COri的接口,其函数的实现就是调用COri的相应接口的函数。换句话说,CExt定义了所有的接口,然后当这些接口是COri原来就有的时候,其内容变成了一个简单的调用。
 
三. 聚合
聚合的思想比较简单,但实现有一些复杂。聚合中并不重新定义一遍COri的接口,而是在实现QueryInterface()的时候,直接返回CExt内部的COri的相应接口指针。换句话说,如果接口是COri中的话,CExt的QueryInterface()函数将直接调用COri的QueryInterface()函数。
这里最大的问题在于,从CExt到COri没有问题,但是如何能够从COri的接口返回到CExt的接口?它们之间可并不是同一层的。
解决的办法是,从一开始COri的接口就要做一些准备工作。首先,COri中必须有一个指针来表明这个对象是单独使用,还是作为CExt的一部分试用。如果是前者,这个指针为NULL,如果是后者,这个指针指向CExt的头,也就是CExt的IUnknown接口。然后,COri的QueryInterface()必须能够判断该指针是否为空,从而在接口查询时能够在必要的时候转而调用CExt的QueryInterface()。
为了使用方便,可以把原来的IUnknown接口以及接口中的函数用另外的名字标记,比如INondelegatingUnknown(书上用这个名字)什么的。当COri不是在被聚合使用的时候,IUnknown接口的函数就去直接调用INondelegatingUnknown接口的函数,实行相应的功能。当COri是被聚合使用的坏死后,IUnknown接口的函数就去调用保存的外部聚合对象CExt的IUnknown接口的函数。
 
四. 包容和聚合的比较
包容比较简单,适用面也大,所有的COM组件都可以被包容。但是包容实际上给CExt多定义了COri的接口函数,做的并不算很漂亮。而且由于这些虚函数都是后期绑定,在编译期无法像一般的函数调用已经直接地址转移节约时间,因此包容的效率比较差。
聚合是真正符合COM要求的重用,其中并没有重复的工作。但是聚合必须要原有的COM组件支持,比如说原有的COM组件有没有实现INondelegatingUnknown接口之类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值