OO开发思想:面向对象的开发方法(Object oriented,OO)

面向对象的开发方法(Object oriented,OO)

    从事软件开发的工程 师们常常有这样 的体会:在软件开发过程中,使用者会不断地提出各种更改要求,即使在软件投入使用后,也常常需要对其做出修改,在用结构化开发的程序中,这种修改往往是很 困难的,而且还会因为计划或考虑不周,不但旧错误没有得到彻底改正,又引入了新的错误;另一方面,在过去的程序开发中,代码的重用率很低,使得程序员的效 率并不高,为提高软件系统的稳定性、可修改性和可重用性,人们在实践中逐渐创造出软件工程的一种新途径――面向对象方法学。

一、面向对象的方法(OO方法)简介

 面向对象方法学的出发点和基本原则是尽可能模拟人类习惯的思维方式,使开发软件的方法与过程尽可能接近人类认识世界、解决问题的方法与过程。由于客观世界的问题都是由客观世界中的实体及实体相互间的关系构成的,因此我们把客观世界中的实体抽象为对象(Object)。持面向对象观点的程序员认为计算机程序的结构应该与所要解决的问题一致,而不是与某种分析或开发方法保持一致,他们的经验表明,对任何软件系统而言,其中最稳定的成分往往是其相应问题论域(problem domain)中的成分。(例如在过去几百年中复式计帐的原则未做任何实质性的改变,而其使用的工具早已从鹅毛笔变成了计算机。)

    所以,“面向对象”是一种认识客观世界的世界观,是从结构组织角度模拟客观世界的一种方法。一般人们在认识和了解客观现实世界时,通常运用的一些构造法则:

  • 区分对象及其属性,例如区分台式计算机和笔记本计算机;

  • 区分整体对象及其组成部分,例如区分台式计算机组成(主机、显示器等);

  • 不同对象类的形成以及区分,例如所有类型的计算机(大、中、小型计算机、服务器、工作站和普通微型计算机等)。

 通俗地讲,对象指的是一个独立的、异步的、并发的实体,它能“知道一些事情” (即存储数据),“做一些工作”(即封装服务),并“与其它对象协同工作”(通过交换消息),从而完成系统的所有功能。

 因为所要解决的问题具有特殊性,所以对象是不固定的。一个雇员可以作为一个对象,一家公司也可以作为一个对象,到底应该把什么抽象为对象,由所要解决的问题决定。

 从以上的简单介绍中我们可以看出,面向对象所带来的好处是程序的稳定性与可修改性(由于把客观世界分解成一个一个的对象,并且把数据和操作都封装在对象的内部)、可复用性(通过面向对象技术,我们不仅可以复用代码,而且可以复用需求分析、设计、用户界面等等)。

 面向对象方法具有下述四个要点:

1. 认为客观世界是由各种对象组成的,任何事物都是对象,复杂的对象可以由比较简单的对象以某种方式组合而成。按照这种观点,可以认为整个世界就是一个最复杂 的对象。因此,面向对象的软件系统是由对象组成的,软件中的任何元素都是对象,复杂的软件对象由比较简单的对象组合而成。

2.把所有对象都划分成各种对象类(简称为类(Class)),每个对象类都定义了一组数据和一组方法,数据用于表示对象的静态属性,是对象的状态信息。因此,每当建立该对象类的一个新实例时,就按照类中对数据的定义为这个新对象生成一组专用的数据,以便描述该对象独特的属性值。

 例如,荧光屏上不同位置显示的半径不同的几个圆,虽然都是Circle类的对象,但是,各自都有自己专用的数据,以便记录各自的圆心位置、半径等等。

    类中定义的方法,是允许施加于该类对象上的操作,是该类所有对象共享的,并不需要为每个对象都复制操作的代码。

3.按照子类(或称为派生类)与父类(或称为基类)的关系,把若干个对象类组成一个层次结构的系统(也称为类等级)。

4.对象彼此之间仅能通过传递消息互相联系。

二、OO方法的基本思想

   对象是事物运行方式、处理方法和属性值的一种抽象表述。它是严格信息包和有关信息包的操作描述;它是事物的本质,不会随周围环境改变而变化的相对固定的最小的集合。它可用一组属性和可以执行的一组操作来定义。

    例:在计算机屏幕上画多边形,每个多边形是一个用有序顶点的集所定义的对象。

    这些顶点的次序决定了它们的连接方式,顶点集定义了一个多边形对象的状态,包括它的形状和它在屏幕上的位置,在多边形上的操作包括:draw(屏幕显示)、 move(移动)、 contains(检查某点是否在多边形内)。

    类是一组具有相同数据结构和相同操作的对象的集合。

    类的定义包括一组数据属性和在数据上的一组合法的操作。在一个类中,每个对象都是类的实例(instance)。同类的对象具有相同的方法集。

    类还具有父类、子类之分。父类高层次的类,表达共性,子类低层次表达个性。子类通过继承机制获得父类的属性和操作。例如:电视机、电话、计算机等都是电子产品,它们具有电子产品的公共特性,当定义电视机类Video,电话类Telephone和计算机类Computer时候,为避免它们公共特性的重复编码,可将这些电子产品的公共特性部分定义为电子产品类,将Video,Telephone和Computer定义为它的子类,子类继承了父类的所有属性和操作,而且子类自己还可扩充定义自己的属性和操作:如电子产品类具有型 、价格、颜色等属性,computer则继承了这些属性,并扩充自己的属性:显示类型、内存大小等属性。

1.发现对象的途经

  它是利用结构化分析的成果,如DFD(数据流程图)、实体关系图、数据字典等,找出和识别对象。
    数据流程图中的数据存储、外部实体,有些非系统内部的数据流(它可来自外部的刺激或系统对外界的响应)等均可以作为候选对象。如存户来银行存款,即是外部对银行存款系统的的一个刺激,其数据内容是存户款;给存户的月终结算,是系统对外部的响应。 

2.对象具有如下特征

   模块性: 对象是一个独立存在的实体。从外部可以了解它的功能,其内部细节是“ 隐蔽”的, 不 受外界干扰。对象之间的相互依赖性很小。所以,模块性体现了抽象和信息的隐蔽。它使得一个复杂的软件系统可以通过定义一组相对独立的模块来实现,这些独立 模块彼此之间只需交换那些为了完成系统功能所必须交换的信息。当模块内部实现发生变化而导致代码修改时,只要对外接口操作的功能不变,就不会给软件系统带 来影响。

    继承和类比性:对象之间属性关系的共同性,即子模块继承了父模块的属性;通过类比方法抽象出典型对象的过程为类比。

    继承:是利用已有的定义作为基础来建立新的定义,而不必重复定义它们。
例如,汽车具有“ 型 ”、“ 年代”和“ 引擎”等属性,其子类吉普车、轿车及卡车都继承了这些属性。

    动态连接性:各个对象之间统一、方便、动态的消息传递机制。它是面向对象语言的共同特性,其含义是将一条发送给一个对象的消息与包含该消息的方法的对象联接起来,它使得增加新的数据类型不需要改变现有的代码。

3.以对象为主体的OO方法

  (1)客观事物都是由对象(object)组成的,对象是在原事物基础上抽象的结果。任何复杂的事物都可以通过对象的组合构成。

   (2)对象由属性(attribute)和方法组成。属性反映了对象的信息特征,如:特点、值、状态等等;方法(method)则是用来定义改变属性状态的各种操作。

    例如:电视机对象的属性有颜色、音量、亮度、频道等,其上的操作有调节颜色、调节音量、调节亮度、调节频道等。

    如:图书馆系统中其业务过程和业务实体中,最基本的对象类只有读者和复本。最基本的业务操作只有借阅和查询。

  (3)对象之间的联系主要是通过传递消息(message)来实现的,而传递的方式是通过消息模式(message pattern)和方法所定义的操作过程来完成的。

    例如当用户请求document的对象打印它自己时,该文档可发送一消息给对象printer以在打印队列中请求一位置,而printer则可发送一消息 返回至该文档以要求对信息加以格式化。消息还可包含解释一请求的信息。如请求一对象打印其自身的消息可包含打印机名。

  (4)对象可按照其属性进行归类(class),类有一定的结构,类上有超类(父类),类下有子类。这种对象或类之间的层次结构是靠继承关系维系着的。一般父类具有通用性,子类具有特殊性。例如:

图4-4-2 对象模型的层次 

    这五个层次很像叠在一起的五张透明塑料片,它们一层比一层显现出对象模型的更多细节。在概念上,这五个层次是整个模型的五张水平切片。

    建立对象模型典型的工作步骤是:首先确立对象类和关联,对于大型复杂的问题还要进一步划分出若干主题;然后给类和关联增添属性,以进一步描述它们;接下来利用适当的继承关系进一步合并和组织类。

(1)确定类-&-对象

    类-&-对象是在问题域中客观存在的,系统分析员的主要任务就是通过分析找出这些类-&-对象。首先,找出所有候选的类-&-对象;然后,从候选的类-&-对象中筛选掉不正确的或不必要的项。

步骤1:找出候选的类-&-对象

    对象是对问题域中有意义的事物的抽象,它们既可能是物理实体,也可能是抽象概念,在分析所面临的问题时,可以参照几类常见事物,找出在当前问题域中的候选类-&-对象。

    另一种更简单的分析方法,是所谓的非正式分析。这种分析方法以用自然语言书写的需求陈述为依据,把陈述中的名高速作为类-&- 对象的候选者,用形容词作为确定属性的线索,把动高速作为服务(操作)候选者。当然,用这种简单方法确定的候选者是非常不准确的,其中往往包含大量不正确 的或不必要的事物,还必须经过更进一步的严格筛选。通常,非正式分析是更详细、更精确的正式的面向对象分析的一个很好的开端。

步骤2:筛选出正确的类-&-对象

    非正式分析仅仅帮助我们找到一些候选的类-&-对象,接下来应该严格考察候选对象,从中去掉不正确的或不必要的,仅保留确实应该记录其信息或需要其提供服务的那些对象。筛选时主要依据下列标准,删除不正确或不必要的类-&-对象:

<1>冗余(如果两个类表达了同样的信息)

<2>无关(仅需要把与本问题密切相关的类-&-对象放进目标系统中)

<3>笼统(需求陈述中笼统的、泛指的名词)

<4>属性(在需求陈述中有些名词实际上描述的是其它对象的属性)

<5>操作(正确地决定把某些词作为类还是作为类中定义的操作)

<6>实现(去掉仅和实现有关的候选的类-&-对象)

()确定关联

    两个或多个对象之间的相互依赖、相互作用的关系就是关联。分析确定关联,能促使分析员考虑问题域的边缘情况,有助于发现那些尚未被发现的类-&-对象。

步骤1.初步确定关联

    在 需求陈述中使用的描述性动词或动词词组,通常表示关联关系。因此,在初步确定关联时,大多数关联可以通过直接提取需求陈述中的动词词组而得出。通过分析需 求陈述,还能发现一些在陈述中隐含的关联。最后,分析员还应该与用户及领域专家讨论问题域实体间的相互依赖、相互作用关系,根据领域知识再进一步补充一些 关联。

步骤2.自顶向下

    把现有类细化成更具体的子类,这模拟了人类的演绎思维过程。从应用域中常常能明显看出应该做的自顶向下的具体化工作。例如,带有形容词修饰的名词词组往往暗示了一些具体类。但是,在分析阶段应该避免过度细化。

()定义结构

    结构指的是多种对象的组织方式,用来反映问题空间中的复杂事物和复杂关系。这里的结构包括两种:分类结构与组装结构。分类结构针对的是事物的类别之间的组织关系,组织结构则对应着事物的整体与部件之间的组合关系。

    使 用分类结构,可以按事物的类别对问题空间进行层次化的划分,体现现实世界中事物的一般性与特殊性。例如在交通工具、汽车、飞机、轮船这几件事物中,具有一 般性的是交通工具,其它则是相对特殊化的。因此可以将汽车、飞机、轮船这几种事物的共有特征概括在交通工具之中,也就是把对应于这些共有特征的属性和服务 放在“交通工具”这种对象之中,而其它需要表示的属性和服务则按其特殊性放在“汽车”、“飞机”、“轮船”这几种对象之中,在结构上,则按这种一般与特殊 的关系,将这几种对象划分在两个层次中,如图4-4-3所示:

  • 描述用户

    应该仔细了解未来使用系统的每类用户的情况,把获得的下列各项信息记录下来:

  •   设计命令层次

设计命令层次的工作通常包含以下几项内容:

所谓命令层次,实质上是用过程抽象机制组织起来的、可供选用的服务的表示形式。

OO开发思想:面向对象的开发方法(Object oriented,OO)精化命令层次

精化命令层次应考虑以下因素:次序、整体—部分关系、操作步骤。

  •   设计人-机交互类

人-机交互类与所使用的操作系统及编程语言密切相关。

(3)设计任务管理子系统

虽 然从概念上说,不同对象可以并发地工作。但是,在实际系统中,许多对象之间往往存在相互依赖关系。此外,在实际使用的硬件中,可能仅由一个处理器支持多个 对象。因此,设计工作的一项重点就是,确定哪些是必须同时操作的对象,哪些是相互排斥的对象。然后进一步设计任务管理子系统。

<1> 分析并发性

彼 此间不存在交互,或者它们同时接受事件,则这两个对象在本质上是并发的。通过检查各个对象的状态图及它们之间交换的事件,能够把若干个非并发的对象归并到 一条控制线中。所谓控制线,是一条遍及状态图集合的路径,在这条路径上每次只有一个对象是活动的。在计算机系统中用任务(task)实现控制线,一般认为任务是进程(process)的别名。通常把多个任务的并发执行称为多任务。

<2> 设计任务管理子系统

常见的任务有事件驱动型任务、时钟驱动型任务、优先任务、关键任务和协调任务等。设计任务管理子系统,包括确定各类任务并把任务分配给适当的硬件或软件去执行。

  • 确定事件驱动型任务

某些任务是由事件驱动的,这类任务可能主要完成通信工作。例如,设备、屏幕窗口、其它任务、子系统、另一个处理器或其它系统通信。事件通常是表明某些数据到达的信 。

  • 确定时钟驱动任务

某些任务每隔一定时间间隔就被触发以执行某些处理,例如,某些设备需要周期性地获得数据;某些人-机接口、子系统、任务、处理器或其它系统也可能需要周期性地通信。在这些场合往往需要使用时钟驱动型任务。

  •   确定优先任务

优先任务可以满足高优先级或低优先级的处理需求。

高优先级:某些服务具有很高的优先级,为了在严格限定的时间内完成这种服务,可能需要把这类服务分离成独立的任务。

低优先级:与高优先级相反,有些服务是低优先级的,属于低优先级处理(通常指那些背景处理)。设计时可能用额外的任务把这样的处理分离出来。

  •   确定关键任务

关键任务是关系到系统成功或失败的那些关键处理,这类处理通常都有严格的可靠性要求。

  •   确定协调任务

当系统中存在三个以上任务时,就应该增加一个任务,用它作为协调任务。

  •   确定资源需求

使用多处理器或固件,主要是为了满足高性能的需求。设计者必须通过计算系统载荷来估算所需要的CPU(或其它固件)的处理能力。

(4)设计数据管理子系统

数据管理子系统是系统存储或检索对象的基本设施,它建立在某种数据存储管理系统之上,并且隔离了数据存储管理模式。

<1> 选择数据存储管理模式

<2> 设计数据管理子系统

设计数据管理子系统,既需要设计数据格式又需要设计相应的服务。设计数据格式包括用范式规范每个类的属性表以及由此定义所需的文件或数据库;设计相应的服务是指设计被存储的对象如何存储自己。

OOP方法( 面向对象实现)

面向对象实现主要包括两项工作:把面向对象设计结果翻译成用某种程序语言书写的面向对象程序;测试并调试面向对象的程序。

面向对象程序的质量基本上由面向对象设计的质量决定,但是,所采用的程序语言的特点和程序设计风格也将对程序的生成、可重用性及可维护性产生深远影响。

1.程序设计

(1)面向对象的语言与非面向对象的语言

到底应该选用面向对象语言还是非面向对象语言,关键不在于语言功能强弱。选择编程语言的关键因素,是语言的一致的表达能力、可重用性及可维护性。从面向对象观点看来,能够更完整、更准确地表达问题和语义的面向对象语言的语法是非常重要的,因为这会带来下述几个重要优点:面向对象语言的形成借鉴了历史上许多程序语言的特点,从中吸取了丰富的营养。当今的面向对象语言,从50年代诞生的LISP语言中引进了动态联编的概念和交到式开发环境的思想,从60年代推出的SIMULA语言中引进了类的概念和继承机制,此外,还受到70年代末期开发的Modula-2语言和Ada语言中数据抽象机制的影响。

100年代以来,面向对象语言像雨后春笋一样大量涌现,形成了两大类面向对象语言。一类是纯面向对象语言,如Smalltalk和Eiffel等语言。另一类是混合型面向对象语言,也就是在过程语言的基础上增加面向对象机制,如C++等语言。

一般说来,纯面向对象语言着重支持面向对象方法研究和快速原型的实现,而混合型面向对象语言的目标则是提高运行速度和使传统程序员容易接受面向对象思想。成熟的面向语言通常都提供丰富的类库和强有力的开发环境。

下面介绍在选择面向对象语言时应该着重考察的一些技术特点。

<1>支持类与对象概念的机制

所有面向对象语言都允许用户动态创建对象,并且可以用指针引用动态创建的对象。允许动态创建对象,就意味着系统必须处理内存管理问题,如果不及时释放不再需要的对象所占用的内存,动态存储分配就有可能耗尽内存。

<2>实现整体–部分结构的机制

一般说来,有两种实现方法,分别使用指针和独立的关联对象实现整体一部分结构。大多数现有的面向对象语言并不显示支持独立的关联对象,在这种情况下,使用指针是最容易的实现方法,通过增加内部指针可以方便地实现关联。

<3>实现一般–特殊结构的机制

既 包括实现继承的机制也包括解决名字冲突的机制。所谓解决名字冲突,指的是处理在多个基类中可能出现的重名问题,这个问题仅在支持多重继承的语言中才会遇 到。某些语言拒绝接受有名字冲突的程序,另一些语言提供了解决冲突的协议。不论使用何种语言,程序员都应该尽力避免出现名字冲突。

<4>实现属性和服务的机制

对于实现属性的机制应该着重考虑以下几个方面:支持实例连接的机制;属性的可见性控制;对属性值的约束。对于服务来说,主要应该考虑下列因素:支持消息连接(即表达对象交互关系)的机制;控制服务可见性的机制;动态联编。

<5>类型检查

程序设计语言可以按照编译时进行类型检查的严格程度来分类。如果语言仅要求每个变量或属性隶属于一个对象,则是弱类型的;如果语法规定每个变量或属性必须准确地隶属于某个特定的类,则这样的语言是强类型的。

<6>效率

许多人认为面向对象语言的主要缺点是效率低。事实上,如有完整类库的面向对象语言,有时能比使用非面向对象语言得到运行更快的代码。这是因为类库中提供了更高效的算法和更好的数据结构。

<7>持久保存对象

<8>参数化类

所 谓参数化类,就是使用一个或多个类型去参数化一个类型的机制,有了这种机制,程序员就可以先定义一个参数化的类模板(即在类定义中包含以参数形式出现的一 个或多个类型),然后把数据类型作为参数传递进来,从而把这个类模板用在不同的应用程序中,或用在同一应用程序的不同部分。Eiffel语言中就有参数化类,C++语言也提供了类模板。

<9>开发环境

(2)程序设计风格

良好的程序设计风格对保证程序质量的重要性。良好的程序设计风格对面向对象实现来说尤其重要,不仅能明显减少维护或扩充的开销,而且有助于在新项目中重用已有的程序代码。

良好的面向对象程序设计风格,既包括传统的程序设计风格和准则,也包括为适应面向对象方法所特有的概念(例如,继承性)而必须遵循的一些新准则。

<1>提高可重用性

面向对象方法的一个主要目标,就是提高软件的可重用性。正如本书11.3节所述,软件重用有多个层次,在编码阶段主要涉及代码重用问题。一般说来,代码重用有两种:一种是本项目内的代码重用,另一种是新项目重用旧项目的代码。内部重用主要是找出设计中相同或相似的部分,然后利用继承机制共享它们。

  • 提高方法的内聚

  • 减小方法的规模

  • 保持方法的一致性

保持方法的一致性,有助于实现代码重用。一般说来,功能相似的方法应该有一致的名字、参数特征(包括参数个数、类型和次序)、返回值类型、使用条件及出错条件等。

  • 把策略与实现分开

  • 全面覆盖

如果输入条件的各种组合都可能出现,则应该针对所有组合写出方法,而不能仅仅针对当前用到的组合情况写方法。

此外,一个方法不应该只能处理正常值,对空值、极限值及界外值等异常情况也应该能够作出有意义的响应。

  • 尽量不使用全局信息

应该尽量降低方法与外界的耦合程度,不使用全局信息是降低耦合度的一项主要措施。

  • 利用继承机制

在面向对象程序中,继承机制是实现共享和提高重用程度的主要途径。

有时提高相似类代码可重用性的一个有效途径,是从不同类的相似方法中分解出不同的“因子”(即不同的代码),把余下的代码作为分用方法中的公共代码,把分解出的因子作为名字相同算法不同的方法,放在不同类中定义,并被这个公用方法调用。

    程序员往往希望重用其它方法编写的、解决同一类应用问题的程序代码。重用这类代码的一个比较安全的途径,是把被重用的代码封装在类中。

<2>  提高健壮性

    为提高健壮性应遵守以下几条准则:预防用户的误操作,不要预先限制条件,先测试后优化。

2、面向对象测试

一般说来,对面向对象软件的测试可分为下列四个层次进行:

(1)算法层

测试类中定义的每个方法,基本上相当于传统软件测试中的单元测试。

(2)类层

测试封装在同一个类中的所有方法与属性之间的相互作用。在面向对象软件中类是基本模块,因此可以认为这是面向对象测试中所特有的模块(单元)测试。

(3)主题层

测试一组协同工作的类-&-对象之间的相互作用。大体上相当于传统软件测试中的子系统测试,但是也有面向对象软件的特点(例如,对象之间通过发送消息相互作用)。

(4)系统层

把各个子系统组装完整的面向对象软件系统,在组装过程中同时进行测试。

设 计测试方案的传统技术,例如,逻辑覆盖、等价划分、边界值分析和错误推测等方法,仍然可以作为测试类中每个方法的主要技术。面向对象测试的主要目标,也是 用尽可能低的测试成本和尽可能少的测试方案,发现尽可能多的错误。但是,面向对象程序中特有的封装、继承和多态等机制,也给面向对象测试带来一些新特点, 增加了测试和调试的难度。

七、面向对象的语言(产品) 面向对象的语言应该具备的特征
    1.用对象而非过程(功能或算法)作为程序设计的基本逻辑构件;
    2.每个对象属于应该类(型),并为该类的一个实例;
    3.一个类可继承其它类的性质。面向对象的语言有:    1.SmallTalk-76,80,(80年代下半叶)

    2.Actor(80年代下半叶)
    3.C++,Objective-C (20世纪80年代下半叶)
    4.Object Pascal, Object-Oriented Turbo Pascal,Apple ObjectPascal (80年代初开始)
    5.Eiffel (80年代上半叶) 

    6.Ada9X 
      但Microsoft Visual C++, Boland C++等都属于混合型面向对象的语言,因为它们是在原来的过程语言的基础上发展起来的,都保留了原来的数据类型,如整数、浮点数、字符以及记录等。

    几个有代表性的商品软件
    Microsoft Visual Basic先从软件的可视化、速成化和组件化开始的,这3化已经开始或正在形成信息与软件工艺的主流之一。
  &nb

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2012年1月25日
下一篇 2012年1月25日

相关推荐