本文先说明COM提供的编程思想,再以此编程思想设计各接口。
作者:lop5712 来源:论坛 2007年10月20日
关键字: 实战 COM 编程
样例目标
欲给一个公司做一个信息管理系统,也就是公司中所有部门的信息可以被输入电脑,并可进行分布式查询,即总经理可随时查询最新的订单情况和出货情况。由于使用COM作为此信息管理系统的基架,可以很容易的解决分布式问题,并且由于COM对安全的包装,使得提供访问控制也变得容易。下面先说明COM提供的编程思想,再以此编程思想设计各接口。
COM编程模型
见过不少这种说法:“COM是更加地面向对象,封装地更彻底”。这里要纠正这种错误的思想,虽然可以说对,但是是错误的应用。这就好像牛刀可以杀鸡,但并不应该被说对。
面向对象编程思想是一种思想,指导如何设计程序架构的。其主打思想就是将被操作数据看成一个个对象。而所谓的对象就是具有状态,并对外提供了接口以暴露其可以提供的服务。其是状态和功能通过语义的混合体。
其和日常生活很像,比如电视机就既提供了服务——搜台,又提供了状态——哪个频道是哪个台。因此在使用面向对象编程思想时会从对象的概念出发来定义数据结构,这和COM完全不一样。
COM叫做组件对象模型,从名字看其异常明显地表示了最开始引号中的话的正确性,这是个误解。COM最突出的贡献不是组件这个概念,而是接口。
接口表示功能的集合,其不是状态。与面向对象正好相反,其完全不看重对象的实现,甚至淡化对象这个概念,极力强调接口的概念,这在各本COM教科书中表现地很明显——里面第一个讲的就是IUnknown接口,极力强调没有对象指针,只有接口指针。
这看起来有点混乱,如果认为面向对象强调的是状态和功能的混合,COM强调的就是功能集的集合。而类就是只实现了一个接口的COM组件(不包括IUnknown),这从根本上说是COM的退化。因此当设计中的每个COM组件都只实现一个接口时,此时根本不是设计一个COM应用,只是在二进制代码级上应用C++提供的编程思想而已。
由于COM做地并不是那么好,以至于会产生前面所说的误解。其强调功能的概念没有体现出来,而更表现为组件,以至于很容易认为组件是积木,而整个程序就是用不同的组件搭建的房子。这是对象级上的模块化编程。COM不会设计到最后反而跑回老路上去。
搭积木的重点是积木,是以积木来搭建房屋。而COM提供的并不是积木,是积木间衔接的形状,它主张在搭积木前先搭一个架子,不同的积木能放到架子上形成的不同的格子里,架子搭好后再根据架子上形成的格子的形状做积木,最后将积木放到架子上。而不是先做积木,然后根据积木搭房屋(这个比喻并不是非常准确)。
思考这个问题:欲实现任务和任务管理器的功能,设计两个接口ITask和ITaskManager,考虑ITask的功能定义。其代表的是能够作用于任务上的功能,不是任务本身,因此其有如下两个方法:TerminateTask和GetProcessRateOfTask以分别终止任务和得到任务进度。但是很明显,任务是需要启动的。如果按照面向对象的思想,在不考虑设计模式的情况下,很容易想到将任务的发起这个动作作为ITask中的一个方法:StartTask,这样ITask的实现者就是一个完全的任务,如果使用线程进行任务操作,其也就连那个线程的操作也一起包装起来,形成一个任务。这不是一个好的设计,ITask是个接口,代表的是功能,不是对象。接口以为实现它的对象就可以照其定义进行操作,因此ITask的实现者是可以被相当于任务一样的操作,而不是任务这个东西。前者具有更好的可扩展性,如可以通过按遥控器来操作东西,但那个东西不一定必须是电视机,而后者就一定要求其是电视机。
因此COM里重点的不是组件,而是接口,这是一种可扩展性相当好的设计思想,可以称做面向接口编程思想。它本身是没有什么缺点的,但其实现方式由于使用对象的概念,则一定和状态关联,这在数据量很大时是不好的。如订单会很容易地就被设计成一个类,然后提供诸如订单结帐、提货等多种服务(即成员函数)。这里的问题就是订单如此之多,如果使用一个数组作为其容器显然性地问题严重,而链表更是应该判死刑。因此这里将订单设计成一个类是很不明智的选择。对于此,应该专门仔细研究如何处理大数据量的技术,并将功能与状态拆开,然后数据变成原材料,而功能变成机器,通过流水线生产以提高效率。即面向对象是个人主义,当数据量大时,就需要分工合作来提高效率了。对于此,Microsoft早已提供了MTS来帮助开发,其中提供的编程思想就是专门针对这种大数据量而设计的,提倡无状态组件,即状态和功能的分离,其对于开发大数据量的应用提供了非常好的支持。