市面上的“设计模式“书籍文章,皆针对Java/C++/C#等面向对象语言,似乎离开了面向对象的种种特性,设计模式就无法实现,没有用武之地了。
是这样吗?设计模式的概念是从建筑领域引入的,本身从没歧视过面向过程编程语言,它只是对一类问题的普遍解决方案而已。面向对象语言因为有类、多态等特点,使得开发者们容易达到:隐藏细节、封装变化,而这与设计模式的目的比较一致,所以大师们爱把设计模式与面向对象语言二位一体的使用。然而,存在即合理,C语言直到今日仍然在大型软件工程中担纲主角,其种种设计方法其实与我们通常见到的设计模式本质是相同的。例如nginx这个纯C语言写就的的高性能WEB服务器,就有许多地方使用到了市面书籍提到的设计模式。下面通过nginx源码来看看C语言是怎么做的。当然,UML图都是我根据代码意图所画,并不准确(C语言真没法画UML),只用于方便理解,呵呵。
strategy模式:
该模式用于客户代码在“无知”状态下,可以使用种种不同的实现。下面我们以nginx对网络IO操作的封装部分来看看C语言的实现吧。
设计模式就是通过封装变化来解耦,所以,我们先要找出网络IO操作的变化点来。nginx是跨平台的,它会支持linux、freebsd、solaris等操作系统,而每个操作系统的网络IO操作是不同的,这就是变化点了。
所以,nginx首先定义了ngx_os_io_t来封装这些变化。
[cpp]
typedef struct { ngx_recv_pt recv; ngx_recv_chain_pt recv_chain; ngx_recv_pt udp_recv; ngx_send_pt send; ngx_send_chain_pt send_chain; ngx_uint_t flags; } ngx_os_io_t; 这里有五个函数指针(*_pt都是函数指针)和一个变量,用于收发网络数据,我把它理解为OO中的abstract class(每个ngx_os_io_t定义的变量都会重新实现这五个函数)。拥有函数指针的struct,我通常认为它们是OO中的abstract class,实现它们的文件(一堆函数)要对应到OO上,我则喜欢把它们当做子类来看。对于void*这样的成员,要根据意图来看了,通常我会转换成聚合加继承的关系。
ngx_io会在相应的ngx_os_specific_init方法中,来策略性的选择到底使用哪个实现。客户代码只需要简单的调用ngx_io中的方法即可。