`
hulunberbus
  • 浏览: 851975 次
文章分类
社区版块
存档分类
最新评论

《BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之13---BREW精要之COM 模型

 
阅读更多

COMComponent Object Model (组件对象模型)的缩写。BREW基本上遵从COM这一组件构架的。组件架构的一个优点就是应用可以随时间的流逝而发展进化,除此之外,使用组件还有一些可以使对以有应用的升级更加方便和灵活的优点,如应用的定制,组件库以及分布式组件等。

BREWCOM属性

COM原本是微软公司为了计算机工业的软件生产更加符合人类的行为方式开发的一种软件开发技术。在COM构架下,人们可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。由此带来的好处是多方面的:可以将系统中的组件用新的替换掉,以便随时进行系统的升级和定制;可以在多个应用系统中重复利用同一个组件;可以方便的将应用系统扩展到网络环境下;COM与语言,平台无关的特性使所有的程序员均可充分发挥自己的才智与专长编写组件模块等等。

BREW SDK中所提供的服务实际上是一些小的二进制可执行程序形成的组件,它们可以给应用程序、操作系统以及其他组件提供服务。开发自定义的BREW组件(例如,BREW 扩展类)就好像是开发动态的、面向对象的API。多个BREW对象可以连接起来形成应用程序或组件系统。并且组件可以在运行时刻,在不被重新链接或编译应用程序的情况下被卸下或替换掉。

COM实际上象结构化编程及面向对象编程方法那样,也是一种编程方法。使用组件的种种优点直接来源于可以将它们动态的插入或卸出应用。为了实现这种功能,所有的组件必须满足两个条件:第一,组件必须动态链接;第二,它们必须隐藏(或封装)其内部实现细节。动态链接对于组件而言是一个至关重要的要求,而消息隐藏则是动态链接的一个必要条件。

总的来说,BREW可以在运行时刻同其他组件连接起来构成某个应用程序,可以动态的插入或卸出应用,是动态链接的。BREW隐藏(封装)其内部实现细节,基于BREW的应用以二进制的形式发布,可以在不妨碍已有用户的情况下被升级。BREW的自定义扩展按照一种标准的方式来宣布它们的存在。

BREW中的接口

COM的对象之间通过接口进行交互。接口是包含了一组函数的数据结构,通过这组数据结构,代码可以调用组件对象的功能。接口定义了一组成员函数,这组成员函数是组件对象暴露给用户的所有可用信息,客户可以利用这些信息取得组件提供的服务。与COM使用GUID作为接口的唯一标识类似,BREW使用称之为ClassID的一个4字节无符号整数作为唯一标识。

BREW提供了一组固定的接口,哪怕以后实现的方式出现了变化,只要应用程序和组件程序之间的接口不变,就不需要任何改变。从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,用户可以调用组件的功能。同样与COM类似,BREW使用基于接口对象的引用计数来控制接口的生存期,并且为多个程序之间共享统一接口对象提供了有效的控制手段。一般来说,引用计数技术包括三种实现方式:一是使用全局引用计数,这样可以精确的控制整个应用程序模块的生存期;二是使用针对每个接口一个引用计数跟踪接口的使用情况,但是对于实现了多个接口的对象,这样做的效果就是分辨率太细这将导致无法精确跟踪每个接口的使用情况,造成管理困难,唯一的好处就是能够减少资源的消耗;三是使用每个对象一个引用计数这样可以精确控制对象的生存期,并且在复杂度和资源消耗上能够达到较好的平衡。BREW接口的引用计数使用方式三,是针对每个接口类或者是应用程序采用引用计数。

应用程序用一个指向接口数据结构的指针来调用接口成员函数,如图4-5所示。<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter" /> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0" /> <v:f eqn="sum @0 1 0" /> <v:f eqn="sum 0 0 @1" /> <v:f eqn="prod @2 1 2" /> <v:f eqn="prod @3 21600 pixelWidth" /> <v:f eqn="prod @3 21600 pixelHeight" /> <v:f eqn="sum @0 0 1" /> <v:f eqn="prod @6 1 2" /> <v:f eqn="prod @7 21600 pixelWidth" /> <v:f eqn="sum @8 21600 0" /> <v:f eqn="prod @7 21600 pixelHeight" /> <v:f eqn="sum @10 21600 0" /> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" /> <o:lock v:ext="edit" aspectratio="t" /> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" alt="" style='width:309.75pt; height:164.25pt'> <v:imagedata src="file:///C:/DOCUME~1/hongweic/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.png" mce_src="file:///C:/DOCUME~1/hongweic/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.png" o:href="http://hiphotos.baidu.com/misstubo/pic/item/0a54e62a79d71829d52af124.jpg" /> </v:shape><![endif]-->

<!--[if supportFields]><span style='mso-element:field-begin'></span><span style="mso-spacerun:yes" mce_style="mso-spacerun:yes">&nbsp;</span>TOC /h /z /c &quot;<span lang=ZH-CN style="font-family:黑体;mso-ascii-font-family: Arial" mce_style="font-family:黑体;mso-ascii-font-family: Arial">图</span>&quot; <span style="mso-element:field-separator" mce_style="mso-element:field-separator"></span><![endif]--> 4-5 BREW应用程序的接口指针示意 <!--[if supportFields]><span style='mso-element:field-end'></span><![endif]-->

实际上,应用所使用的接口指针也指向一个指针,这个指针则指向一组函数的定义(即接口函数表,又称为虚函数表,vtable)。每一个接口成员函数的第一个参数必须为指向这个定义这个接口的组件类型的指针(可以参考一下用C模拟C++的过程,在C++的类定义中,每一个成员函数的第一个参数都是隐含的,即编译系统自动添加的this指针),这是因为接口本身不能独立存在,它必须依附于某个COM组件而存在。因此这个指针可以提供对象实例的属性信息,在调用过程中可以知道是在对那个COM对象进行操作。 图中到圆边方框之前,定义的都是指针,真正的实现要依赖于COM组件给出的实现,对于客户来说,只需要知道应该调用什么就足够了,但是对于组件来说就必须考虑这样的功能应该怎样实现。接口是客户程序和组件程序之间的桥梁,接口应该具有不变性,并且一个COM对象也应该支持多个接口。

对于同一个类的所有对象,它们分别拥有不同的数据成员存储区,但是共享同一份成员函数的拷贝,在不同的对象调用成员函数的时候根据对象隐式传递的this指针判别是哪个对象调用了成员函数。对于接口的实现也类似,类似于C++中的数据成员,对于指向虚函数表的指针,每个接口指针都有属于自己的一份拷贝,而对于提供功能实现的虚函数表,则共享同一份拷贝(图4-6)。

<!--[if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" alt="" style='width:382.5pt;height:102.75pt'> <v:imagedata src="file:///C:/DOCUME~1/hongweic/LOCALS~1/Temp/msohtmlclip1/01/clip_image003.png" mce_src="file:///C:/DOCUME~1/hongweic/LOCALS~1/Temp/msohtmlclip1/01/clip_image003.png" o:href="http://hiphotos.baidu.com/misstubo/pic/item/7ee6e013c47ebf065baf5324.jpg" /> </v:shape><![endif]-->

<!--[if supportFields]><span style='mso-element:field-begin'></span><span style="mso-spacerun:yes" mce_style="mso-spacerun:yes">&nbsp;</span>TOC /h /z /c &quot;<span lang=ZH-CN style="font-family:宋体;mso-ascii-font-family: "Times New Roman";mso-hansi-font-family:"Times New Roman"" mce_style="font-family:宋体;mso-ascii-font-family: "Times New Roman";mso-hansi-font-family:"Times New Roman"">图</span>&quot; <span style='mso-element:field-separator'></span><![endif]--> 4-6 BREW中的虚函数表 <!--[if supportFields]><span style='mso-element:field-end'></span><![endif]-->

BREW中的ISHELL_createlnstance方法使用了对象创建型设计模式的抽象工厂模式,它提供了创建一系列相关或者是相互依赖对象的接口,而无须指定他们具体的类,这样可以只提供BREW 的接口,而在需要的时候根据具体的ClassID创建具体的实现,一般来说抽象工厂模式有以下的几个优点:

(1)分离了具体的实现和接口:只需指定不同的接口和classlD,既可成功创建接口对象,而无须关心是何种实现;

(2)有利于更新产品模块:当有新的模块更新的时候,无须更改程序,只需替换相应的模块实现,这样就可以使用新的模块;

(3) 有利于产品的一致性;由于classID的唯一性,可以创建指定的对象实现,而不会在有众多实现的应用中出现混乱。

对于抽象工厂模式难以支持新种类产品的缺点,在BREW 的设计架构中给予消除了,由于重新启动BREW环境的时候,会对系统范围内的ClassID 予以重新注册,因此当新种类加入的时候,只需要提供确定的ClassID 既可成功创建应用。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics