忽悠一下在C++中使用IoC和DSM (1 & 2)

kjin101 2007-12-18 01:54:56
自Web和Java诞生以来,软件开发技术,概念以及架构的演变翻新有点让人眼花缭乱,甚至应接不暇。然而,恪守技术含量至上遗风的C++铁杆精英们似乎是其中的另类,与标新立异摈弃繁文褥节的Java,Ruby新生代之间俨如隔世。不用说DSM,就连IoC这个起源于C+ +年代甚至C++土壤的概念和方法虽然在墙外其他晚辈语言部落中广受青睐,在C++红墙内却反而遭长期冷落。IoC和DSM技术虽然看似简单无比平淡无奇遍地都是,甚至被很多C++大老们嗤之以鼻,但却能大大提升C++软件开发的效率及质量,而且能彻底简化和净化很多繁琐丑陋甚至危险的C++原始解决方案。比如,由IBM领头忽悠的一个所谓“服务组件架构”SCA(Service Component Architecture)的厂商标准,其C++组件容器的参考实现(RI)虽由IBM几个老大全时操刀,历时两年却���然困难重重地蹒跚在Apache孵化项目阶段。不仅如此,这个沿用传统思维和方法的参考实现使用起来也相当繁琐,甚至危险(用户将被迫采用无类型验证系统的C-style cast),并且有很多极不自然甚至丑陋的限制(比如对线程模型的特殊要求)(参见 SCA considered harmful 一文)。与之对比,如果采用IoC和DSM技术去实现同样的SCA C++组件容器,一个初级菜鸟程序员却能在几天甚至几小时内以区区数百行浅显易懂的代码轻而易举地大功告成,且其结果还远胜于IBM老大们呕心沥血打造的参考版(易用,类型安全,清除所有不合理限制)(参见 SCA as a DSM 一文)。此类事半功倍的例子在使用IoC和DSM框架的开发中屡见不鲜。其开发效率一个数量级以上的跳跃改进也绝非天方夜谭。70年代关系数据库及SQL技术的引入就使数据库应用的开发效率提高了近两个数量级。 

1. IoC

IoC 字面上的意思是“控制反转”(Inversion of Control)。然而其具体含义五花八门的说法却很容易让人一头雾水。这些说法往往是过多地关注IoC表面的甚至是字面的含义,却忽略了IoC 被用来解决的实质问题(也无视了这个概念的历史和使用现状)。Martin Fowler 就把IoC阐述甚至更名为“依赖注入”(Dependency Injection )设计模式。而IoC鼻祖之一 Stefano Mazzocchi 却指出Martin Fowler这个忽悠了一大批人的说法实际上是不得要领(Martin Fowler文章中代码例子确实非常误导)。所以,这里并不急于给IoC下一个教条定义,而是从IoC的实质目的开始探讨。

IoC 的概念是Michael Mattson在1996年一篇讨论面向对象框架(Object Oriented Frameworks)的文章中提出的。面向对象设计及编程(OOD/OOP)的基本思想简单地说就是把复杂软件系统分解成通过接口相互合作的对象。这些对象类的内部实现之间并不互相牵扯,因而降低了问题的复杂性,且可独立灵活地被重用和扩展。自然而然,经典面向对象的编程语言(如C++,Java)的侧重点就是提供语言机制来方便并简化这种基于对象类的分解,重用和扩展。然而,一个软件系统的开发效率,可扩展性,以及部署维护升级的灵活性等并不完全由其模块化分解的程度和抽象的优劣所决定。很大程度上,能否有效清晰而又灵活地再将这些相对独立制作的分散部件组装成一个紧密合作的整体并完成其部署和配置更是决定该软件项目成败及其产品系统优劣的关键。

以支持对象分解为己任的经典面向对象语言(如C++,Java)并没有引入超越传统命令式语言(imperative language)以外的系统组装部署和配置手段(当然,Java 5,C#现在都开始往这方面添料)。因而,虽然它们能够有效地应付底层子系统的拼装和连接,但在进行大范围基于组件(既高层业务层模块)层次的相应作业时就显得简陋,死板,冗长和低效。比如,在使用各种std的IO流类,STL容器类以及boost库类这些底层模块类时,采用语言本身的机制(自动变量或用 new算符)直截了当地实例化这些被使用类的对象就尽善尽美了。但在使用高层业务模块时,为了避免对其具体实现类的的静态依赖,人们不得不叠床架屋对语言机制进行额外的手工包装。应运而生的是一系列处理所谓管线逻辑(plumbing logic,既非业务逻辑)的设计模式,比如factory,builder,directory,adaptor,singleton, configuration/property manager,factory的manager甚至manager的manager等等。遗憾的是,一个世纪以来这些实际上是弥补语言缺陷的权宜之计反而受到狂热追捧而非深入反思。另外,在传统软件的设计和实现中,业务逻辑往往直接调用这些管线逻辑,从而破坏了业务逻辑的简洁性和独立性(比如增加了单元测试的困难)。更重要的是,软件组装部署和配置的逻辑是支离破碎地散落混迹于各个业务逻辑组件中,既不直观(往往是见树不见林)也不灵活(牵一发则可能动全身)。往往使得在宏观结构上理解,维护,修改和扩充一个现有软件要反而难于当初从头开发这个软件。 

为解决以上问题,Michael Mattson提出了面向对象框架的IoC设计原则。依照该原则,管线逻辑被转移并集中至软件框架内,业务逻辑模块并不需知道更不必调用组件框架的服务,例如不用关心和调用其factory或lookup其directory或context等。软件的组装部署和配置完全是由管线逻辑框架反过来主动控制业务逻辑模块来安排。Michael Mattson用所谓的好莱坞原则(Hollywood Principle)“别来电(问)我,我会去电(告诉)你”(don't call me, I will call you)形象地比喻了这一设计思想。这个比喻中的“我”指的是负责管线逻辑的组件框架,“你”则是被其调遣配置的一个组件。比如,在一个业务逻辑模块A需要调用另一个业务逻辑模块B的场景中,传统的非IoC的设计(比如EJB2.0)是让A调用管线逻辑(B的factory或某个directory服务)来获得B的引用(或指针)。在IoC框架内,框架不但完成A和B的实例化并保持追踪,而且B的实例引用(或指针)也是由框架主动调用A的接口函数(比如构造及赋值函数等)赋予 A。从而,A的实现可以专著于业务逻辑,而管线细节(比如B的实例化及如何获得其引用或指针)可以让外部框架透明地安排妥当。这种架构完全避免了业务逻辑对具体管线逻辑框架的牵连从而降低了业务逻辑模块的复杂度,但更重要的是集中的组装部署和配置逻辑为提高软件宏观结构的直观性和灵活性铺平了道路(后面还将具体讨论)。

简短概括一下,从概念上说,IoC就是模块化软件组装部署配置框架的一个设计原则。依该原则,业务逻辑模块既不需要处理管线逻辑也可以对外部管线框架本身一无所知(agnostic)。软件的搭接完全由外部管线框架对业务逻辑模块的主动操控来完成。从具体实现上说,除了一些开发工具以外,IoC框架不过是一个封装了必备的管线逻辑及IoC机制的轻型类库(比如PocoCapsule/C++ IoC类库大约是70K)。从使用上说,用户制作好业务逻辑组件(见下面非侵入性与POCO讨论),并将软件组装及部署描述(见后面讨论)提供给IoC框架(作为 IoC框架库函数的调用参量,或直接驱动一系列库函数调用)。IoC容器(被调用的库函数)将参照用户的描述相应地实例化和配置各个组件并将它们搭接为所希望的部署状态。 

2. 非侵入性与POCO

对于象C++和Java这类不支持动态类型的语言环境,一个很自然的问题就是业务逻辑组件需要支持什么样的公共接口以使外部IoC框架能对其进行操控。早期的组件框架(比如Apache Avalon,EJB2.0,CORBA组件模型 CCM,JTRS-SCA等)几乎清一色地采用侵入式(invasive)设计,也就是强制规定业务逻辑模块(称作bean)必须与特定的公共组件接口模型兼容,既支持由组件框架定义的用来对组件进行部署配置的公共接口类型或基类(base class)以及进行实例化的所谓home接口。侵入式设计不仅学习和使用繁琐(EJB2.0和CCM均是以繁为完美的恶例),也大大地限制了组建框架的开放性和适应性。因为众口难调,所以几乎每一个问题领域均定义了N个自己的组件框架和组件接口模型(比如机器人领域里就至少有10个)。侵入式设计导致组件接口模型只能被其特定的框架所支持,从而形成了各自为政老死不相往来的组件框架孤岛,限制了组件的重用范围以及框架的通用性。大量这类侵入式组件框架以及与之相应的上下左右整个配套开发体系(如果侥幸有的话)均仅仅是在小范围内被采用,并以高成本在低水平上无谓地被重复开发和维护(CCM就是这方面最恶名昭著的例子)。 

因此,现代IoC框架大都采用非侵入式(non-invasive)设计,也就是不对组件接口模型(即接口及函数签名)做任何规定。换句话说,非侵入的 IoC框架一视同仁地支持任何组件接口模型,包括已经被定义的和还未被定义的模型,也包括标准组织定义的或用户自定义的模型。这些组件接口模型可以采用(或不采用)任何公共或自定义接口,模板(template)或基类(也可以根本不是C++对象,比如是C/C++函数),可以采用任何(合理的)实例创建/生命控制回收手段和部署配置函数,包括构造或析构函数,各种自定义duplicate/release/factory/pool/directory lookup函数,以及各种全局或成员函数等(参见开源C++非侵入式IoC框架项目 PocoCapsule/C++ IoC的介绍 )。在非侵入的C++ IoC组件框架中,因为所有组件无论其接口模型的新旧美丑高矮胖瘦均被一视同仁地按平头百姓对待,故均被统称为“平庸C++对象”(Plain Old C++ Object )或POCO(相应于Java中的“平庸Java对象”POJO)。

待续...

======

版主补充

忽悠一下在C++中使用IoC和DSM (3&4)
http://topic.csdn.net/u/20071218/14/1ae337cb-4a7b-4eef-ba82-0346339df3ca.html
忽悠一下在C++中使用IoC和DSM (5)
http://topic.csdn.net/u/20071218/14/6707a5af-1ee9-45fc-acc4-80330fb4ba89.html
...全文
551 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
天乐_那由他 2008-11-21
  • 打赏
  • 举报
回复
十分的不错,对IOC的理解很有帮助啊。
组件的部署确实是个需要认真对待的大问题。
谭建新 2008-11-16
  • 打赏
  • 举报
回复
mark
lyskyly 2008-10-19
  • 打赏
  • 举报
回复
mark一下
lyskyly 2008-10-19
  • 打赏
  • 举报
回复
mark一下
kiffa 2008-10-16
  • 打赏
  • 举报
回复
听起来非常美,问题是框架真能做的那么好吗?尤其是采用非侵入式设计之后,很难想像可以有个通用的框架。

搬凳子看后续,然后再发表意见。

sandrowjw 2008-07-17
  • 打赏
  • 举报
回复
恩,好玩
knowledge_Is_Life 2008-05-01
  • 打赏
  • 举报
回复
等待牛人来答.
meiZiNick 2008-05-01
  • 打赏
  • 举报
回复
关注 接分
UltraBejing 2008-05-01
  • 打赏
  • 举报
回复
我也想了解,谢谢LZ.
mimong_lin 2007-12-27
  • 打赏
  • 举报
回复
看得不是太懂.MARK下,再看.
kjin101 2007-12-24
  • 打赏
  • 举报
回复
这俩名词都不是我起的,而且都是有年头的了。。。。
iambic 2007-12-23
  • 打赏
  • 举报
回复
这两个名词也太难看了吧。
kjin101 2007-12-22
  • 打赏
  • 举报
回复
是自己瞎写的。多谢WOLF版主鼓励!
kjin101 2007-12-22
  • 打赏
  • 举报
回复
是自己瞎写的。多谢WOLF版主鼓励!
wshcdr 2007-12-20
  • 打赏
  • 举报
回复
healer_kx是个 叛徒啊叛徒
healer_kx 2007-12-19
  • 打赏
  • 举报
回复
很好,我很多C++的实践收益于Java那里学来的模式。

Wolf0403 2007-12-19
  • 打赏
  • 举报
回复
原创?不错。
kjin101 2007-12-18
  • 打赏
  • 举报
回复
<http://blog.csdn.net/kjin101/archive/2007/12/16/1941057.aspx>
Wolf0403 2007-12-18
  • 打赏
  • 举报
回复

出处何方?

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧