为了统一各种面向对象方法的术语、概念和模型,1997年推出了统一建模语言(Unified Modeling Language,UML
)。
它是面向对象的标准建模语言,通过统一的语义和符号表示,使各种方法的建模过程和表示统一起来,现在已经成为面向对象建模的工业标准。
(一)面向对象的基本概念
识别面向对象的方法:
面向对象 = 对象(Object)+ 分类(Classification)+ 继承(Inheritance)+ 通过消息的通信(Communication with Messages)
1. 对象
在面向对象的系统中,对象是基本的运行时的实体,它既包括数据(属性),也包括作用于数据的操作(行为)。
2. 消息
对象之间进行通信的一种构造叫消息。
当一个消息发送给某个对象时,包含要求接收对象去执行某些活动的信息。接收到信息的对象经过解释,然后予以响应。这种通信机制称为消息传递。
3. 类
一个类定义了一组大体上相似的对象。一个类包含的方法和数据描述一组对象的共同行为和属性。
类是在对象之上的抽象,对象是类的具体化,是类的实例。
类可以分为三种:实体类、接口类(边界类)和控制类。
4. 继承
继承是父类和子类之间共享数据和方法的机制。
一个父类可以有多个子类,父类描述了这些子类的公共属性和方法,一个子类可以继承它的父类(或祖先类)中的属性和方法,这些属性和操作在子类中不必定义,子类中还可以定义自己的属性和方法。
5. 多态
在收到消息时,对象要予以回应。不同的对象收到同一消息可以产生完全不同的结果,这一现象称为多态。
6. 动态绑定
绑定是一个把过程调用和响应调用所需要执行的代码加以结合的过程。
在编译时进行的绑定,叫静态绑定;在运行时进行的绑定叫动态绑定。
动态绑定是和类的继承以及多态相联系的。在继承关系中,子类是父类的一个特例,所以父类对象可以出现的地方,子类对象也可以出现。因此在运行过程中,当一个对象发送消息请求服务时,要根据接收对象的具体情况将请求的操作与实现的方法进行连接,即动态绑定。
(二)面向对象分析
面向对象分析(OOA
)的目的是为了获得对应用问题的理解。
面向对象分析包含的五个活动:认定对象、组织对象、描述对象间的相互作用、确定对象的操作、定义对象的内部信息。
1. 认定对象
在应用领域中,按自然存在的实体确立对象。
在定义域中,首先将自然存在的“名词”作为一个对象。
2. 组织对象
分析对象间的关系,将相关对象抽象成类,利用类的继承性建立具有继承性层次的类结构。
3. 对象间的相互作用
描述出各对象在应用系统中的关系,如一个对象是另一个对象的一部分,一个对象与其他对象间的通信关系等。这样可以完整地描述每个对象的环境,由一个对象解释另一个对象,以及一个对象如何生成另一个对象,最后得到对象的界面描述。
4. 基于对象的操作
基于对象的操作,有从对象直接标识的简单操作,如创建、增加和删除等;也有更复杂的操作,如将几个对象的信息连接起来。
一般而言,避免对象太复杂比较好,当连接的对象太复杂时,可将其标识为新对象。
(三)面向对象设计
面向对象设计(OOD
)是将面向对象分析(OOA
)所创建的分析模型转化为设计模型,其目标是定义系统构造蓝图。
1. 面向对象设计的活动
面向对象设计在复用面向对象分析模型的基础上,包含与面向对象分析对应如下五个活动:
- 识别类及对象
- 定义属性
- 定义服务
- 识别关系
- 识别包
面向对象设计应该尽可能隔离实现条件对系统的影响,对不可隔离的因素按实现条件调整面向对象分析模型。
2. 面向对象设计原则
- 单一责任原则(
SRP
)
当需要修改某个类的时候原因有且仅有一个,让一个类只做一种类型责任。 - 开发-封闭原则(
OCP
)
类、模块、函数等应该是可以扩展的,即开放的;但是不可修改的,即封闭的。 - 里氏替换原则(
LSP
)
子类型必须能够替换他们的基类型。 - 依赖倒置原则(
DIP
)
抽象不应该依赖于细节,细节应该依赖于抽象。即,高层模块不应该依赖于低层模块,二者都应该依赖于抽象。 - 接口分离原则(
ISP
)
不应该强迫客户依赖于它们不用的方法。即,依赖于抽象,不要依赖于具体,同时在抽象级别不应该有对于细节的依赖。
上述五项是面向对象方法中的五大原则,除了这五项外,还提出了以下几项设计原则:
- 重用发布等价原则(
REP
)
重用的粒度就是发布的粒度。 - 共同封闭原则(
CCP
)
包中所有的类对于同一类性质的变化应该是共同封闭的。 - 共同重用原则(
CRP
)
一个包中的所有类应该是共同重用的。 - 无环依赖原则(
ADP
)
在包的依赖关系中不允许存在环。 - 稳定依赖原则(
SDP
)
朝着稳定的方向进行依赖。 - 稳定抽象原则(
SAP
)
包的抽象程度应该和其稳定程度一致。
(四)面向对象程序设计
面向对象程序设计(OOP
)的实质是选用一种面向对象程序设计语言(OOPL
),采用对象、类及其相关概念所进行的程序设计。
1. 类
类具有实例化功能,包括实例生成和实例消除。
类的特征:
- 同一个类的不同实例具有相同的数据结构,承受的是同一方法集合所定义的操作,因而具有规律相同的行为
- 同一个类的不同实例可以持有不同的值,因而可以具有不同的状态
- 实例的初始状态可以在实例化时确定
2. 继承和类层次结构
孤立的类只能描述实体集合的特征同一性,而客观世界中实体集合的划分通常还要考虑实体特征方面有关联的相似性,在面向对象程序设计中使用继承来解决这一问题。
当执行一个子类的实例生成方法时,首先在类层次结构中从该子类沿继承路径上溯到它的一个基类,然后自顶向下执行该子类所有父类的实例生成方法;最后执行该子类实例生成方法的函数体。
3. 对象、消息传递和方法
对象是类的实例。
消息传递源是一种与通信有关的概念,对象被看成用传递消息的方式互相联系的通信实体,它们既可以接收,也可以拒绝外界发来的消息。
发送一条消息至少应给出一个对象的名字和要发送给这个对象的那条消息的名字。通常,消息的名字就是这个对象中外界可知的某个方法的名字。
4. 对象自身引用
对象自身引用在面向对象程序设计语言中有不同的名称,在C++
和Java
中称为this
,在Object-C
中称为self
。
对象自身引用的值使得方法体中引用的成员名与特定的对象相关,对象自身引用的类型则决定了方法体被实际共享的范围。
对象自身引用机制使得在进行方法的设计和实现时并不需要考虑与对象联系的细节,而是从更高一级的抽象层次,也就是类的角度来设计同类型对象的行为特征,从而使得方法在一个类及其子类的范围内具有共性。
5. 重置
重置或覆盖是在子类中重新定义父类中已经定义的方法,其基本思想是通过一种动态绑定机制的支持,使得子类在继承父类接口定义的前提下用适合自己要求的实现去置换父类中的相应实现。
6. 类属类
类属是程序设计语言中普遍注重的一种参数多态机制。
类属类可以看成是类的模板。一个类属类是关于一组类的一个特性抽象,它强调的是这些类的成员特征中与具有类型无关的那些部分,而与具体类型相关的那些部分则用变元来表示。
7. 无实例的类
在C++
和Java
中,抽象类就是无实例的类。
(五)面向对象测试
程序调试步骤是从最底层开始的,从单元测试、综合测试到系统测试。
- 单元测试是系统构件的分体测试
- 将测试好的系统构件接起来看它们之间相互作用的正确性称为综合测试
- 最后是整个系统的测试,包括软件系统所在环境的测试
对面向对象软件的测试可以分为下列四个层次进行:
- 算法层
测试类中定义的每个方法,基本上相当于传统软件测试中的单元测试。 - 类层
测试封装在同一个类中的所有方法与属性之间的相互作用,可以认为这是面向对象测试中所特有的模块测试。 - 模板层
测试一组协同工作的类之间的相互作用,大体上相当于传统软件测试中的集成测试。 - 系统层
把各个子系统组装成完整的面向对象软件系统,在组装过程中同时进行测试。