面向对象分析方法是在一个系统的开发过程中进行了系统的业务调查之后,安装面向对象的思想来分析问题。OOA 与结构化分析有较大的区别。OOA 强调的是在系统调查的资料基础之上,针对 OO 方法所需要的素材进行的归类分析和整理,而不是对管理业务现状和方法的分析。
OOA 模型分为 5 个层次(主题层、对象类层、结构层、属性层、服务层),和 5 个活动(标识对象类、标识结构、定义主题、定义属性、定义服务)。在这种方法中定义了两种对象之间的结构,一种称为分类结构,一种称为组装结构。分类结构就是所谓的一般与特殊的关系(即继承)。组装结构则反映了对象之间的整体和部分的关系(即组合)。
OOA 定义属性的同时,要识别实例连接。即一个实例与另一个实例的映射关系。
OOA 在定义服务的同时要识别消息连接。当一个对象需要另一个对象发送消息时,它们直接就存在消息连接。
OOA 中的 5 个层次和 5 个活动会继续贯穿在 OOD 过程中。OOD 模型由由 4 个部分组成:设计问题域、设计人机交互、设计任务管理、设计数据管理。
抽象的定义:从许多事物中社区个别的、非本质的特征,抽取共同的、本质性的特征,就叫做抽象。抽象是形成概念的必要手段。
抽象原则有两方面的意义:第一,尽管问题域中的问题是复杂的,但是分析员并不需要了解它们的一切,只需要分析研究其中与系统目标有关的事物及其本质性特征;第二,通过舍弃个体事物在细节上的差异,抽取其共同特征而得到的一批事物的抽象概念。
抽象是面向对象方法中最为广泛的原则。抽象包括过程抽象和数据抽象两个部分。
过程抽象是指:任何一个完成确定功能的操作序列,其使用者都可以把它看做一个单一的实体,尽管实际上它可能是有一系列更低级的操作完成的。
数据抽象是指:根据施加于数据之上的操作来定义数据类型,并限定数据的值只能由这些操作来修改和访问。数据抽象是 OOA 的核心原则。它强调把数据(属性)和操作(服务)结合为一个不可分割的系统单位(即对象),对象的外部只能知道它能做什么,而不知道它具体如何做。
封装就是把对象的属性和服务结合为一个不可分割的系统单位,并尽可能隐藏对象的内部细节。
特殊(具体)类的对象拥有的其一般类的全部属性和服务,称作特殊类对一般类的继承。
在 OOA 中运用继承原则的过程,就是在每一个由一般类和特殊类形式的一般——特殊结构中,把一般类的对象实例和所有特殊类的对象实例都共同具有的属性和服务,一次性的在一般类中进行显式的定义。在特殊类中不再重复地定义一般类中已定义的东西,但是在语义上,特殊类却自动地、隐含地拥有它的一般类(以及所有更上一层的一般类)中定义的全部属性和服务。
继承原则的好处是,是系统模型比较简练且清晰。
就是把具有相同属性和服务的对象划分为一类,用类作为这些对象的描述抽象。分类原则实际上是抽象原则应用于对象描述时的一种表现形式。
又称组装,其原则是:把一个复杂的事物看成若干个比较简单的事物的组装体,从而简化对复杂事物的描述。
是人类思考问题是经常运用的思想方法:通过一个事物联想到另外的事物。能使人发生联想的原因是事物之间确实存在着某些联系。
该原则要求对象之间只能通过消息进行通信,而不允许在对象之外直接的存取对象内部的属性。通过消息进行通信是由于封装原则而引起的。在 OOA 中要求用消息连接表示出对象之间的动态联系。
一般来讲,人在面对一个复杂的问题域时,不可能在同一时刻即可纵观全局,又能够洞察秋毫。因此需要控制字节的视野:考虑全局时,注意其大的组成部分,暂时不详查每一部分的具体细节;考虑某部分的细节时则暂时撇开其余的部分。这就是粒度控制原则。
现实世界中事物的行为是复杂的。由大量的事物所构成的问题域中各种行为往往相互依赖、相互交织。
实用 OOA 具体分析一个事物时,大致遵循以下五个基本步骤:
面向对象设计方法是 OO 方法中一个过渡环节。其主要作用是对 OOA 分析的结果做出进一步规范化的整理,以便能够直接被 OOP 直接接受。
OOD 是一种软件设计方法,是一种工程化规范。这是毫无疑问的,按照 Bjarne Stroustrup(C++ 之父) 的说法,面向对象的编程范式:
由这个定义,我们可以看出:OOD 就是“根据需求决定所需的类、类的操作,以及类之间关联的过程”。
OOD 的目标是管理程序内部各个部分之间的相互依赖。为了达到这个目标,OOD 要求将程序分块,每个块的规模应该小到可以被管理的程度,然后分别将各个块隐藏在接口后面,让它们仅通过接口相互交流。比如说,如果用 OOD 的方法来设计一个服务端——客户端应用,那么服务器和客户端之间不应该有直接的依赖,而是应该让服务器的接口和客户端的接口相互依赖。
这种依赖关系的转换使得系统各部分具有了可复用性。还是拿上面那个例子来说,客户端就不必依赖于特定的服务器,所以就可以复用到其他的环境下。如果要复用一个程序块,只要实现必须的接口就可以了。
OOD 是一种解决软件问题的设计范式、一种抽象的范式。使用 OOD 这种设计范式,我们可以用对象来表现问题领域的实体,每个对象都有相应的状态和行为。我们刚才说到:OOD 是一种抽象的范式。抽象可以分很多层次,从非常概括到非常具体的都有,而对象可能处于任何一个抽象实层次上。另外,彼此不同但又互有关联的对象可以共同构成抽象:只要这些对象之间有相似性,就可以把它们当成同一类对象来处理。
计算机硬件技术飞速发展,从十几年前神秘的庞然大物,到现在随身携带的移动芯片;从每秒数千次运算到每秒上百亿次运算。当软件开发者们还在寻找能让软件开发生产力提供一个量级的银弹时,硬件开发的生产力早已提高了百倍千倍。
硬件工程师们能够如此高效,是因为他们都很懒惰。它们永远恪守不要去重复发明轮子的古训。Grady Booch 把这些黑箱称为类属(class category),现在我们则通常把它们称之为组件(component)。
类属是由被称为类(class)的实体组成,类与类之间通过关联(relationship)结合在一起。一个类可以把大量的细节隐藏起来,只暴露出一个简单的接口,这正好符合人们喜欢抽象的心理。所以,这是一个非常伟大的理念,因为它给我们提供了封装和复用的基础,让我们可以从问题的角度来看问题,而不是从机器的角度来看问题。
软件的复用最初是从函数库和类库开始的,这两种复用形式实际上都是白箱复用。到 90 年代,开始有人开发并出售黑箱软件模块:框架(framework)和控件(control),框架和控件往往还受平台和语言的限制,现在软件技术的新潮流是使用 SOAP 作为传输介质的 Web Service,它可以使软件模块脱离平台和语言的束缚,实现跟高程度的复用。但是想一想,其实 Web Service 也是面向对象,只不过是把类与类之间的关联使用 XML 来描述而已。
在过去十多年里,面向对象技术对软件行业起到了极大的推动技术。在可以预测的未来,它仍将是软件设计的主要技术——至少我们暂时看不到有什么技术能够取代它。
有很多人认为:OOD 是对结构化设计(structured design, SD)的扩展,其实这是不对的。OOD 的设计观念和 SD 完全不同。SD 注重的是数据结构和处理数据结构的过程,而在 OOD 中,过程和数据结构都被对象隐藏了起来,两者几乎是互不相关的。不过,追根溯源,OOD 和 SD 有着非常深的渊源。
1967 年前后,OOD 和 SD 的概念几乎同时诞生,他们分别以不同的方式来表现数据结构和算法。当时,围绕着这两个观念,很多科学家写了大量的论文。其中,由 Dijkstra 和 Hoare 两人缩写的一些论文讲到了“恰当的程序控制结构”这个话题,声称 goto 语句是有害的,应该用顺序、循环、分支这三种控制结构来构成整个程序流程。这些概念发展成了结构化程序设计方法;而由 Ole-Johan Dahl 所写的另一些论文则主要讨论编程语言中的单位划分,其中的一种程序单位就是类,它已经拥有了面向对象程序设计的主要特征。
这两种概念立刻就分道扬镳了。在结构化这边的历史大家都很清楚:NATO 会以采纳了 Dijksta 的思想,整个软件产业都同意 goto 语句的确是有害的,结构化方法、瀑布模型从 70 年代开始大行其道。同时,无数的科学家和软件工程师也帮助结构化方法不断发展完善,其中有很多在今天足以使我们震耳发聩的名字,例如 Constantine、Yourdon、DeMarco、Dijkstra。有很长一段时间,整个世界都相信:结构化方法就是拯救整个软件工业的银弹。当然,时间最后证明了一切。
而此时,面向对象则在研究和教育领域缓慢发展。结构化程序设计几乎可以应用于任何编程语言之上,而面向对象程序设计则需要语言的支持,这也妨碍了面向对象技术的发展。实际上,60 年代后期,支持面向对象特性的语言只有 Simula-67 这一种。到 70 年代,施乐帕洛阿尔托研究中心(PARC)的 Alan Key 等人发明了另一种基于面向对象方法的语言,那就是大名鼎鼎的 Smalltalk。但是,直到 80 年代中期,Smalltalk 和另外几种面向对象语言仍然只停留在实验室里。
到 90 年代,OOD 就突然风靡了整个软件行业,这绝对是软件开发史上的一次革命。不过,登高才能望远,新事物总是站在旧事物的基础之上。70 年代和 80 年代的设计方法揭示出许多有价值的概念,谁都不能忽视它们,OOD 也一样。
还记得结构化设计方法吗?程序被划分为几个模块,这些模块被组织成一个树形结构。这棵树的根就是主模块,叶子就是工具模块和最低级的功能模块。同时,这棵树也表示调用结构:每个模块都调用字节的直接下级模块,并被自己的直接上级模块调用。
那么,哪个模块负责收集应用程序最重要的策略呢?当然是最顶端的那些。在低下的那些模块只管实现最小的细节,最顶端的模块关心规模最大的问题。所以,在这个体系结构中越靠上,概念的抽象层次就越高,也越接近问题领域;体系结构中位置越低,概念就越接近细节,与问题领域的关系就越少,而与解决方案领域的关系就越多。
但是,由于上方的模块需要调用下方的模块,所以这些上方的模块就依赖于下方的细节。换句话说,与问题领域相关的抽象要依赖于与问题领域无关的细节!这也就是说,当实现细节发生变化时,抽象也会受到影响。而且,如果我们想复用某一个抽象的话,就必须把它依赖的细节都一起托过去。
而在 OOD 中,我们希望倒转这种依赖关系:我们创建的抽象不依赖于任何细节,而细节则高度依赖于上面的抽象。这种依赖关系的倒转正是 OOD 和传统技术之间根本的差异,也正是 OOD 思想的精华所在。
对于 OOA 所抽象出来的对象、类,及汇集的分析文档,OOD 需要有一个根据设计要求整理和求精的过程,使之更能符合 OOP 的需要。这个整理和求精的过程主要有两个方面:第一,是要根据面向对象的概念、模型,整理分析所确定的对象的结构、属性、方法等内容,删除重复和不必要的内容等;第二,是进行分类整理,以便下一步数据库设计和程序处理模块的需要。整理的方法主要是进行归类,对类、对象、属性、方法、结构、主题进行归类。
数据模型的设计需要确定类、对象属性的内容、消息连接的方式、系统访问、数据模型的方法等。最后每个对象实例的数据都必须落到面向对象的库结构模型中。
OOD 的优化设计过程是从另一个角度对分析结果和处理业务过程的整理归纳,优化包括对象和结构的优化、抽象、集成。
对象和结构的模块化表示 OOD 提供了一种范式,这种范式支持对类和结构的模块化。这种模块化符合一般模块化所要求的所有特点,如信息隐蔽性好、内部聚合度强、模块之间耦合度弱等。
集成化使得单个构件有机地结合在一起,相互支持。
OO 方法以对象为基础,利用特定的软件工具直接完成从对象可观的描述到软件结构之间的转换。这是 OO 方法最主要的特点和成就。OO 方法的应用解决了传统结构化开发方法中客观世界描述工具与软件结构的不一致性问题,缩短了开发周期,解决了从分析和设计到软件模块之间多次转换映射的繁杂过程,是一种很有发展前途的系统开发方法。
但是同原型方法一样,OO 方法需要一定的软件基础支持才可以应用,另外在大型的 MIS 开发中如果不经自定向下的整体划分,而是一开始就自底向上的采用 OO 方法开发系统,同样会造成系统结构不合理、各部分关系失调等问题。所以 OO 方法和结构化方法目前仍是两种在系统开发领域相互依存的、不可替代的方法。
问这个问题的人,脑子里通常是在想“OOD 能解决所有的设计问题吗?”。没有银弹。OOD 也不是解决一切设计问题、避免软件危机、捍卫世界和平……的银弹。OOD 只是一种技术。但是,它是一种优秀的技术,它可以很好地解决目前大多数软件设计问题——当然,这要求设计者有足够的能力。
OOD 可能会让你头疼,因为要学会它、掌握它是很困难的;OOD 甚至会让你失望,因为它也并不成熟、并不完美。OOD 也会给你带来欣喜,它然你可以专注于设计,而不必操心那些细枝末节;OOD 也会使你成为一个更好的设计师,它能提供给你很好的工具,让你能够开发出更坚固、更可复用、更可维护的软件。
面向对象编程(Object Oriented Programming, OOP)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到了软件工程的三个主要目标:重用性、灵活性、扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其他对象发送信息。OOP 主要有一下概念和组件:
由于抽象性、封装性、重用性以及便于使用等方面的原因,以组件为基础的编程在脚本语言中已经变得特别流行。Python 和 Ruby 是最近才出现的语言,在开发时完全采用了 OOP 的思想,而流行的 Perl 脚本语言从版本 5 开始也慢慢加入了新的面向对象的功能组件。用组件代替“现实”上的实体成为 Javascript 得以流行的原因,有论证表名对组件进行适当组合就可以在因特网上代替 HTML 和 XML 的文档对象模型(DOM)。