分类: C/C++
2012-01-04 14:03:04
章中所谈到的内容就让人非常兴奋,因为在那个国内热火朝天学习设计模式的几年里,这几篇文章因为其内
容涉及到了bridge, strategy, adapter, facade等模式在这个网络通信框架中实打实的应用,让我切身体
会到了面向对象设计模式的强大火力。同时因为这几篇文章绝不是我们在学习模式应用时想当然的东西,决
不是简单的几句玩笑或不成熟的例子所能同日而语。所以我感觉还是把这几篇文章中的核心内容保存到网上
比较好。
(从美国海军到CERN物理实验室,从Boeing Advanced Avionics Systems到都能看到这两个软件的踪影)
他是中间件技术的先驱之一,在相关领域发表了百余篇学术论文。 包括Microsoft在内的许多公司都受到了注:因为这篇文章不是面向初学者的文章,而是对那些有一定模式使用经验,同时也对上面所说的那几
种设计模式有一定心得的朋友。相信当您看到本文中所说的几个模式的应用场景和最终的实现结果后,会有
某些心得。
统一起来、并得以自动化,ACE提供了叫做ACE_Reactor的事件多路分离和事件处理器分派框架。同时,为
了保证应用的可移植性,无论是在何种操作系统上,也无论底层使用了何种事件多路分离机制,ACE_Reactor
路分离机制(比如在Windows上既可以使用WaitForMultipleObjects(),也可以使用select())。
Bridge模式正是ACE_Reactor具有这样的灵活性和可移植性的关键所在。
上面所描述的ACE_Reactor接口及相关接口,在 ACE支持的各种平台上都是相同的,但因为这些平台
提供的多路分离机制各不相同,所以在开发ACE_Reactor 时,必须为不同的平台提供不同的具体实现。要
达到这一目的,一般的做法是为每种平台定义一个继承自 ACE_Reactor类的子类,在子类中提供该平台专
用的具体实现。 但正如GoF在Design Pattern一书中所说,这样的继承把实现与抽象永久性地绑定在一起,
使得我们难以独立地修改、扩展和复用各种抽象和实现。正是基于这样的考虑,ACE的开发者在实现
ACE_Reactor时,采用了Bridge模式。
下图以ACE_Select_Reactor和ACE_WFMO_Reactor为例,说明了体现在ACE_Reactor中的Bridge
模式:
定义ACE_Reactor抽象的接口,并维护有一个指针reactor_impl_,指向Implementor类型的一个对象。
许多操作都将通过该指针转发给具体的Implementor对象。
在ACE中没有定义RefinedAbstraction,但如果你想要对 ACE_Reactor接口进行扩展,就可以定义自
己的。
ConcreteImplementor(ACE_Select_Reactor和ACE_WFMO_Reactor)
实现Reactor_Impl接口,并定义其具体实现。除了这里提到的到的ACE_Select_Reactor和
ACE_WFMO_Reactor,在ACE 中还定义了ACE_Dev_Poll_Reactor(基于“/dev/poll”或 “/dev/epoll”
的Reactor实现)和ACE_TP_Reactor(支持基于线程池的事件分派)等其他类型的Reactor。详情可查阅
ACE 的参考文档:
因为ACE_Reactor的实现采用了Bridge模式,我们在使用ACE_Reactor时拥有很大的灵活性。比如说,
在Windows 平台上,系统提供的WaitForMultpleObjects()同时只能在64个句柄上等待,而ACE_WFMO
_Reactor 在使用了2个句柄进行内部管理,所以如果你使用的是 ACE_WFMO_Reactor,实际上只能同时
等待62个句柄,对于大型应用来说,这往往是不够的(显然,这个问题并非是Douglas C. Schmidt的错,
而是Bill Gates的错)。如果你不需要使用ACE_WFMO_Reactor提供的一些特别的功能(比如等待同步事
件),你可以改用ACE_Select_Reactor来进行事件多路分离:
ACE_Select_Reactor select_reactor;
ACE_Reactor reactor (&select_reactor);
... ...在ACE中包含有两种不同的内存管理类。一组基于ACE_Alloctor类,它们使用了动态绑定及Strategy
模式来提供灵活性及可扩展性。其局限是它们只能用于进行局部动态内存管理。下面是ACE_Alloctor类的
部分定义(C++):
下面是继承自ACE_Alloctor的三种Alloctor(注:ACE_Cached_Allocator实际上继承自ACE_NEW_Alloctor。
除这里列出的Alloctor以外,ACE还提供了其他Alloctor。详情参见ACE相关文档)如下:
这个Alloctor 管理固定尺寸的内存。每次收到内存请求时,它都移动某个内部指针,并返回内存Chunk(大块)。
它假定内存一经分配,就不会再被释放。
这个Alloctor预先分配一个内存池,其中含有一定数目的指定尺寸的chunk。这些chunk被维护在内部的一个free
list上,并在收到内存请(malloc())时返回。应用调用free()时,chunk返回内存的free list ,而不是OS.
这三种Alloctor使用了一同的内存分配策略(strategy),适用于不同的情况。比如在实时系统中,有可能必须使
用预先分配内存的ACE_Cached_Allocator,用以获取高性能和可预测性。因为这些ACE_Cached_Allocator都继
承自ACE_Allocator,所以它们拥有相同的接口,可以在编译时或运行时相互替换---但同时,因为这样的能力
是通过虚函数获得的,它们也要付出相应的代价:额外的间接层次来的时间开销(本人注:可参见候捷先生的《c++
对象模型深度探索》一书)。
在前面的strategy模式中我们说到了ACE的内存管理类。其实在ACE中还有另外一组基于ACE_Malloc模板类的
内存管理类。这一组类使用了C++模板和外部多态性来提供内存分配的灵活性。它们不仅能够管理局部动态内存,也
能够管理进程间的共享内存。因为它们与基于ACE_Allocator的类不同,没有使用继承和动态绑定,所以性能更高。
它们只能在编译时,通过其将要使用的内存池配置,而不能在运行时配置。显示,尽管其类效率更高,却不如ACE_
Allocator 灵活。
如上所示,ACE_Malloc需要两个模板参数,一个是内存池类,一个是加锁类。而ACE中有以下几种不同的内
存池。
现在考虑这种情况:ACE中大多数容器类都允许传入Allocator,用于管理容器中的内存。而这些内存分配方
式只有基于ACE_Malloc 的类才能提供。如果要使用这些内存分配方式该怎么办呢?在已经拥有了ACE_Malloc
的情况下,重写新的Allocator 肯定不是好的选择。而这时已出现了Adapter模式中所提到的应用场景中的两个,
即:
typedef ACE_Allocator_Adapter<ACE_Malloc<ACE_SHARED_MEMORY_POOL, ACE_Nul_Mutex>>
SMP_Allocator;
这个SMP_Allocator可以用于任何需要Allocator接口的地方。但其底层使用的却是拥有共享进程池(ACE_SHARED_
MEMORY_POOL)的ACE_Malloc的功能。因为到这里我们可以推断出ACE_Static_Allocator,ACE_Cached_Allocator,
ACE_New_Allocator 与 ACE_Allocator_Adapter 均继承自ACE_Allocator。而事实也确实是这样。
模板类。Adaptee是基于ACE_Malloc的类。Request是Malloc和Calloc等方法,而SpecificRequest()是基于
ACE_Malloc的类的Malloc和Calloc等方法。而这即是Adapter Object中的类关系图,如下:
下面接着说一下Facade模式。
Facede 为例。在这些ACE类中(下面会进行说明)使用Facade模式,将“面向连接”的Socket API功能封
装成了可移植的C++ 类。即将现有的非面向对象API所提供函数和数据封装到了简要,健壮,可移植,可维
护的面向对象类的接口中。
ACE_SOCK_CONNECTOR:这是一个工厂,它链接至一个对等的接收者,然后在一个
ACE_SOCKET_Stream对象中初始化
ACE_SOCK_Acceptor:这是一个工厂,它在一个ACE_SOCKET_Stream对象中初始化一个新的通信
端点,对“来自对等连接者的连接请求”做出响应。
1.提高了类型安全,可以很快发现应用程序中很多微妙的类型错误,例如若用于“被动和主动建立连接”
的工厂没有提供“发送和接收数据”的方法,那么,类型错误在编译时就可以发现,而不是运行时。
3.简化了常见的使用情况,因为减少了应用程序代码量,节省了耗费在“低级网络编程细节”上的开发量,
开发者可以将注意力庥中在高级的,“以应用为中心”的问题上。
4.另外还保留了效率,它通过使用内联函数,提高了软件质量,且没有牺牲性能。好的,到这里,今天的内容差不多就要结束了,因为只是罗列内容,所以没什么太多的思考,只是一次
回顾而已。
tag:ACE,Douglas C. Schmidt,马维达
作者:代震军,daizhj
原文链接:http://www.cnblogs.com/daizhj/archive/2008/08/18/1270085.html