`
softstone
  • 浏览: 459997 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

深入浅出OOD(一)

阅读更多

深入浅出OOD(一)

撰文/透明<!----><o:p></o:p>

(本文首发于免费电子杂志《C++ View》。)<o:p></o:p>

有物昆成,先天地生。萧呵!谬呵!独立而不改,可以为天地母。吾未知其名,字之曰道。吾强为之名曰大,大曰逝,逝曰远,远曰反。道大,天大,地大,王亦大。<o:p></o:p>

——《道德经》,第二十五章<o:p></o:p>

软件不软

60年代的软件危机,到今天传统软件工程方法处处碰壁的处境,都说明一个问题:软件不软(Software is Hard[Martin, 95]。说实话,软件是一块硬骨头,真正开发过软件的人都会有此感觉。一个应用总是包含无数错综复杂的细节,而软件开发者则要把所有这些细节都组织起来,使之形成一个可以正常运转的程序,这实在不是一件简单的事。

为什么会这样?举个例子来说:用户可以很轻松地说“我要一个字处理软件”,他觉得“字处理软件”这样一个概念是再清楚不过的了,根本不需要更多的描述;而真正开发一个字处理软件却是一件困难无比的事情——我曾经亲眼看到开发字处理软件的人们是怎样受尽折磨的。为什么表述一个概念很容易,而实现一个概念很困难?因为人们太擅长抽象、太擅长剥离细节问题了。

软件不软,症结就在这里:用户很容易抽象地表达自己的需求,而这种抽象却很难转化为程序代码。软件不软,因为很简单的设想也需要大量的时间去实现;软件不软,因为满足用户的需求和期望实在太困难;软件不软,因为软件太容易让用户产生幻想。

而另一方面,计算机硬件技术却在飞速发展。从几十年前神秘的庞然大物,到现在随身携带的移动芯片;从每秒数千次运算到每秒上百亿次运算。当软件开发者们还在寻找能让软件开发生产力提高一个数量级的“银弹”[Brooks, 95]时,硬件开发的生产力早已提升了百倍千倍。这是为什么?

硬件工程师们能够如此高效,是因为他们都很懒惰。他们永远恪守“不要去重新发明轮子”的古训,他们尽量利用别人的成果。你看到有硬件工程师自己设计拨码开关的吗?你看到有硬件工程师自己设计低通滤波电路的吗?你看到有硬件工程师自己设计计时器的吗?他们有一套非常好的封装技术,他们可以把电路封装在一个接插件里面,只露出接口。别人要用的时候,只管按照接口去用,完全不必操心接插件内部的实现。

而软件工程师们呢?在STL成为C++标准之前(甚至之后),每个C++程序员都写过自己的排序算法和链表,并认为自己比别人写得更好……真是令人伤心。

OOD可以让软件稍微“软”一点

软件不软,不过OOD可以帮助它稍微“软”一点。OOD为我们提供了封装某一层面上的功能和复杂性的工具。使用OOD,我们可以创建黑箱软件模块,将一大堆复杂的东西藏到一个简单的接口背后。然后,软件工程师们就可以使用标准的软件技术把这些黑箱组合起来,形成他们想要的应用程序。

Grady Booch把这些黑箱称为类属(class category,现在我们则通常把它们称为“组件(component)”。类属是由被称为类(class的实体组成的,类与类之间通过关联(relationship结合在一起。一个类可以把大量的细节隐藏起来,只露出一个简单的接口,这正好符合人们喜欢抽象的心理。所以,这是一个非常伟大的概念,因为它给我们提供了封装和复用的基础,让我们可以从问题的角度来看问题,而不是从机器的角度来看问题。

软件的复用最初是从函数库和类库开始的,这两种复用形式实际上都是白箱复用。到90年代,开始有人开发并出售真正的黑箱软件模块:框架(framework)和控件(control)。框架和控件往往还受平台和语言的限制,现在软件技术的新潮流是用SOAP作为传输介质的Web Service,它可以使软件模块脱离平台和语言的束缚,实现更高程度的复用。但是想一想,其实Web Service也是面向对象,只不过是把类与类之间的关联用XML来描述而已[Li, 02]。在过去的十多年里,面向对象技术对软件行业起到了极大的推动作用。在可以预测的将来,它仍将是软件设计的主要技术——至少我看不到有什么技术可以取代它的。

上面,我向读者介绍了一些背景知识,也稍微介绍了OOD的好处。下面,我将回答几个常见的问题,希望能借这几个问题让读者看清OOD的轮廓。

什么是OOD

面向对象设计(Object-Oriented DesignOOD)是一种软件设计方法,是一种工程化规范。这是毫无疑问的。按照Bjarne Stroustrup的说法,面向对象的编程范式(paradigm)是[Stroustrup, 97]

l        决定你要的类;<o:p></o:p>

l        给每个类提供完整的一组操作;<o:p></o:p>

l        明确地使用继承来表现共同点。<o:p></o:p>

由这个定义,我们可以看出:OOD就是“根据需求决定所需的类、类的操作以及类之间关联的过程”。

OOD的目标是管理程序内部各部分的相互依赖。为了达到这个目标,OOD要求将程序分成块,每个块的规模应该小到可以管理的程度,然后分别将各个块隐藏在接口(interface)的后面,让它们只通过接口相互交流。比如说,如果用OOD的方法来设计一个服务器-客户端(client-server)应用,那么服务器和客户端之间不应该有直接的依赖,而是应该让服务器的接口和客户端的接口相互依赖。

这种依赖关系的转换使得系统的各部分具有了可复用性。还是拿上面那个例子来说,客户端就不必依赖于特定的服务器,所以就可以复用到其他的环境下。如果要复用某一个程序块,只要实现必须的接口就行了。

OOD是一种解决软件问题的设计范式(paradigm),一种抽象的范式。使用OOD这种设计范式,我们可以用对象(object)来表现问题领域(problem domain)的实体,每个对象都有相应的状态和行为。我们刚才说到:OOD是一种抽象的范式。抽象可以分成很多层次,从非常概括的到非常特殊的都有,而对象可能处于任何一个抽象层次上。另外,彼此不同但又互有关联的对象可以共同构成抽象:只要这些对象之间有相似性,就可以把它们当成同一类的对象来处理。

OOD到底从哪儿来?

有很多人都认为:OOD是对结构化设计(Structured DesignSD)的扩展,其实这是不对的。OOD的软件设计观念和SD完全不同。SD注重的是数据结构和处理数据结构的过程。而在OOD中,过程和数据结构都被对象隐藏起来,两者几乎是互不相关的。不过,追根溯源,OODSD有着非常深的渊源。

1967年前后,OODSD的概念几乎同时诞生,它们分别以不同的方式来表现数据结构和算法。当时,围绕着这两个概念,很多科学家写了大量的论文。其中,由DijkstraHoare两人所写的一些论文讲到了“恰当的程序控制结构”这个话题,声称goto语句是有害的,应该用顺序、循环、分支这三种控制结构来构成整个程序流程。这些概念发展构成了结构化程序设计方法;而由Ole-Johan Dahl所写的另一些论文则主要讨论编程语言中的单位划分,其中的一种程序单位就是,它已经拥有了面向对象程序设计的主要特征。

这两种概念立刻就分道扬镳了。在结构化这边的历史大家都很熟悉:NATO会议采纳了Dijkstra的思想,整个软件产业都同意goto语句的确是有害的,结构化方法、瀑布模型从70年代开始大行其道。同时,无数的科学家和软件工程师也帮助结构化方法不断发展完善,其中有很多今天足以使我们振聋发聩的名字,例如ConstantineYourdonDeMarcoDijkstra。有很长一段时间,整个世界都相信:结构化方法就是拯救软件工业的“银弹”。当然,时间最后证明了一切。

而此时,面向对象则在研究和教育领域缓慢发展。结构化程序设计几乎可以应用于任何编程语言之上,而面向对象程序设计则需要语言的支持[1],这也妨碍了面向对象技术的发展。实际上,在60年代后期,支持面向对象特性的语言只有Simula-67这一种。到70年代,施乐帕洛阿尔托研究中心(PARC)的Alan Key等人又发明了另一种基于面向对象方法的语言,那就是大名鼎鼎的Smalltalk。但是,直到80年代中期,Smalltalk和另外几种面向对象语言仍然只停留在实验室里。

90年代,OOD突然就风靡了整个软件行业,这绝对是软件开发史上的一次革命。不过,登高才能望远,新事物总是站在旧事物的基础之上的。70年代和80年代的设计方法揭示出许多有价值的概念,谁都不能也不敢忽视它们,OOD也一样。

OOD和传统方法有什么区别?

还记得结构化设计方法吗?程序被划分成许多个模块,这些模块被组织成一个树型结构。这棵树的根就是主模块,叶子就是工具模块和最低级的功能模块。同时,这棵树也表示调用结构:每个模块都调用自己的直接下级模块,并被自己的直接上级模块调用。

那么,哪个模块负责收集应用程序最重要的那些策略?当然是最顶端的那些。在底下的那些模块只管实现最小的细节,最顶端的模块关心规模最大的问题。所以,在这个体系结构中越靠上,概念的抽象层次就越高,也越接近问题领域;体系结构中位置越低,概念就越接近细节,与问题领域的关系就越少,而与解决方案领域的关系就越多。

但是,由于上方的模块需要调用下方的模块,所以这些上方的模块就依赖于下方的细节。换句话说,与问题领域相关的抽象要依赖于与问题领域无关的细节!这也就是说,当实现细节发生变化时,抽象也会受到影响。而且,如果我们想复用某一个抽象的话,就必须把它依赖的细节都一起拖过去。

而在OOD中,我们希望倒转这种依赖关系:我们创建的抽象不依赖于任何细节,而细节则高度依赖于上面的抽象。这种依赖关系的倒转正是OOD和传统技术之间根本的差异,也正是OOD思想的精华所在。

OOD能给我带来什么?

问这个问题的人,脑子里通常是在想“OOD能解决所有的设计问题吗?”没有银弹。OOD也不是解决一切设计问题、避免软件危机、捍卫世界和平……的银弹。OOD只是一种技术。但是,它是一种优秀的技术,它可以很好地解决目前的大多数软件设计问题——当然,这要求设计者有足够的能力。

OOD可能会让你头疼,因为要学会它、掌握它是很困难的;OOD甚至会让你失望,因为它也并不成熟、并不完美。OOD也会给你带来欣喜,它让你可以专注于设计,而不必操心那些细枝末节;OOD也会使你成为一个更好的设计师,它能提供给你很好的工具,让你能开发出更坚固、更可维护、更可复用的软件。

C++是一种“真正的”面向对象编程语言吗?

最后这个问题和我们今天的主题关系不大,不过这是一个由来已久的问题,而且以后也不一定会有合适的时机说明这个问题,所以今天一起回答了。

很多人都觉得C++缺少“真正的”面向对象语言所必须的一些特性,例如垃圾收集(garbage collection)、多分配(multiple-dispatch)之类的。但是,缺少这些特性并不影响开发者们用C++实现面向对象的设计思路。

在我看来,任何语言,只要它直接支持面向对象设计的实现,那它就是“真正的”面向对象语言。用这个标准来评价,C++是完全符合的:它直接支持继承、多态、封装和抽象,而这些才是面向对象最重要的。而VBC这样的语言不能直接支持这些(尽管可以用特殊的技巧来实现),所以不是“真正的”面向对象语言。

参考书目

l        [Brooks, 95]       Frederick Brooks, The Mythical Man-Month, Addison-Wesley, 1995.

l        [Li, 02]       李维,《Delphi 6/Kylix 2 SOAP/Web Service程序设计篇》,机械工业出版社,2002年。

l        [Martin, 95]       Robert Martin, Designing Object-Oriented C++ Applications Using the Booch Method, Prentice-Hall, 1995.

l        [Stroustrup, 97]       Bjarne Stroustrup, The C++ Programming Language (Special Edition), Addison-Wesley, 1997.



[1] 我听见有人说“我可以用C语言实现面向对象”,不过我希望你不会说“我也喜欢这样做”。很明显,如果没有语言特性的支持,面向对象方法将寸步难行。其实结构化设计也是一样,不过几乎所有的编程语言都提供了对三种基本流程结构的支持,所以基本不会遇到这个问题。

分享到:
评论

相关推荐

    headfirstOOA&OOD Part4

    HeadFirst系列OOA和OODPart4

    李維新書--面向对象实践之路(Delphi版)--第八篇 <img src="/ima

    李維又出新書了介紹引用如下:本书主要介绍了利用主流开发方法学和技术技巧进行面向对象开发的原则与实践,通过完整剖析一个实际应用程序的设计、开发与实现,深入浅出地阐述OOD(面向对象开发)、OOP(面向对象程序...

    李維新書--面向对象实践之路(Delphi版)--導讀篇 <img src="/ima

    李維又出新書了介紹引用如下:本书主要介绍了利用主流开发方法学和技术技巧进行面向对象开发的原则与实践,通过完整剖析一个实际应用程序的设计、开发与实现,深入浅出地阐述OOD(面向对象开发)、OOP(面向对象程序...

    李維新書--面向对象实践之路(Delphi版)--第四章 <img src="/ima

    李維又出新書了介紹引用如下:本书主要介绍了利用主流开发方法学和技术技巧进行面向对象开发的原则与实践,通过完整剖析一个实际应用程序的设计、开发与实现,深入浅出地阐述OOD(面向对象开发)、OOP(面向对象程序...

    面向对象开发实践之路(Delphi版)

     本书主要介绍了利用主流开发方法学和技术技巧进行面向对象开发的原则与实践,通过完整剖析一个实际应用程序的设计、开发与实现,深入浅出地阐述ood(面向对象开发)、oop(面向对象程序设计)、tdd(测试驱动开发...

    headfirstOOA&OOD Part3

    HeadFirst系列OOA和OODPart3

    面向对象开发实践之路:DELPHI版(带完整书签)

     本书主要介绍了利用主流开发方法学和技术技巧进行面向对象开发的原则与实践,通过完整剖析一个实际应用程序的设计、开发与实现,深入浅出地阐述ood(面向对象开发)、oop(面向对象程序设计)、tdd(测试驱动开发...

    headfirstOOA&OOD Part1

    HeadFirst系列之OOA和OODesign

    headfirstOOA&OOD Part2

    HeadFirst系列OOA和OODPart2

    headfirstOOA&OOD Part6

    HeadFirst系列OOA和OODPart6

    headfirstOOA&OOD Part7

    HeadFirst系列OOA和OODPart7

    headfirstOOA&OOD Part5

    HeadFirst系列OOA和OODPart5

    测试驱动的面向对象软件开发

    《测试驱动的面向对象软件开发》采用通俗易懂的比喻,众所周知的编程语言,短小精悍的工作实例,深入浅出的分析处理——仿佛在和几位世界级的编程高手一边喝茶,一边聊天,循序渐进地让读者在不知不觉中进入编程的最高...

    活用UML-软件设计高手

    同时讲师有多年的授课经验,讲课深入浅出,注重引导学员思考,通过大量的实例让学员掌握知识。讲师是每日培训缔造者,是讲师的训练师。 课程特点 1.将UML知识融汇中具体的实例中,而不会单调地讲UML语法。 2.案例一...

    活用UML-由需求到设计

    同时讲师有多年的授课经验,讲课深入浅出,注重引导学员思考,通过大量的实例让学员掌握知识。讲师是每日培训缔造者,是讲师的训练师。 课程特点 1.将UML知识融汇中具体的实例中,而不会单调地讲UML语法。 2.案例一...

    asp.net知识库

    深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白 asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托...

Global site tag (gtag.js) - Google Analytics