3 类与对象
OOAD的基本构建块就是类和对象。
3.1 对象的本质
3.1.1 什么是对象,什么不是对象
一个对象是一个具有状态、行为和标识符的实体。
结构和行为类似的对象定义在他们共同的类中。
“实例”和“对象”这两个术语可以互换使用。
3.1.2 状态
对象的状态包括这个对象的所有属性(通常是静态的)以及每个属性当前的值(通常是动态的)。(自动售货机的例子)
相对于数字,对象是有存在时间的、可以变化的、有状态的、可以实例化的,可以被创建、销毁和共享。
3.1.3 行为
行为是对象在状态改变和消息传递方面的动作和反应的方式。
对象的行为代表了它外部可见的活动。
一个对象的所有方法è它的协议è对象允许行为的封装
一个对象的状态和行为共同决定了这个对象可以扮演的角色。
角色动态且互斥。
对象像自动机è主动对象VS被动对象
3.1.4 标识符
一个对象的属性,来区分这个对象与其他所有对象。
3.2 对象之间的关系
3.2.1 链接
端到端的关系或客户/服务提供者的关系
控制器:操作别人,箭头向外
服务器:被操作,箭头向内
代理:双向(或无箭头)
引发问题:可见性,同步(顺序、守卫(客户互斥使用)、并发(服务保证互斥))
3.2.2 聚合
部分/整体的关系
3.3 类的本质
3.3.1 什么是类,什么不是类
类是一组对象,它们拥有共同的结构、行为和语义。
一个对象就是类的一个实例。
3.3.2 接口和实现
类的接口提供了它的外部视图。类的实现是它的内部视图。
根据可见性,再将接口区分为:公,保,私,包
接口(即声明)主要为所有的操作声明(适用于该类的所有对象),也可能包含其他类、常量、变量和异常的声明。
3.3.3 类的生命周期
某些类在每个实例生命周期的不同阶段涉及不同操作è时间次序、事件次序
3.4 类之间的关系
3.4.1 关联
语义上的依赖关系
多重性:一对一、一对多、多对多
3.4.2 继承
一般/特殊的关系
继承的替代方法是委托
单继承: 扩展继承、限制继承;子类从父类中继承结构和行为
多态:重载运算符/函数为初级形态;延迟绑定
多继承: 名字冲突è加限定符;重复继承è虚继承;混入类(仅用于多继承的抽象类)
3.4.3 聚合
整体/部分关系。
【聚合 VS组合】
聚合弱,空心箭头,生存期不同,按引用包容
组合强,实心箭头,生存期相同,按值包容
【聚合 VS关联】
关联关系所涉及的两个类是处于同一层次上的
而在聚合关系中,两个类处在不平等的层次上的,一个代表整体,一个代表部分。
(关联与聚合仅仅从语法上是区分不开的,需要察所涉及的类之间的逻辑关系。)
3.4.4 依赖关系
依赖是类与类之间的连接,一般是以下几种情况之一:
a、ClassA中某个方法的参数类型是ClassB;这种情况成为耦合;
b、ClassA中某个方法的参数类型是ClassB的一个属性;这种情况成为紧耦合;
c、ClassA中某个方法的实现实例化ClassB;
d、ClassA中某个方法的返回值的类型是ClassB;
如果出现了上述四种情况之一,两个类很有可能就是“依赖”关系。
关联是一种结构关系,说明一个事物的对象与另一个事物的对象相联系;
关联在代码中一般表示为属性(成员变量)
【关联和依赖的区别】
从类之间关系的强弱程度来分,关联强,依赖较弱;
从类之间关系的时间角度来分,关联表示类之间的“持久”关系,需要保存;
依赖表示类之间的是一种“临时、短暂”关系,不需要保存;
3.5 类与对象的互动
3.5.1 类与对象的关系
3.5.2 类与对象在分析和设计中的角色
在分析阶段和设计早期:
任务1:从问题与的词汇表中确定出类
任务2:创建一些结构,让多组对象一起工作,提供满足需求的行为
将这样的类和对象统称为问题的“关键抽象”,把这些协作结构称为实现的“机制”
设计前期,关注外部视图;设计后期和实现阶段,关注内部视图和物理实现
3.6 创建高品质的类与对象
3.6.1 评判一种抽象的品质
低耦合(高扇入、低扇出)
高内聚
充分性(够用,最小接口)
完整性(所有方面,通用)
基础性(访问底层才能实现的)
3.6.2 选择操作
1)功能语义
将一个行为提取为一个方法:简单接口,大方法 è无法管理的大模块
将一个行为分散到多个方法:复杂接口,简单方法 è片段化
判定是否将一个操作/方法加入到一个类的条件:
- 可复用性: 在多种上下文中使用
- 复杂性: 实现难度
- 适用性: 与类之间的相关度
- 实现知识: 是否依赖类的内部细节
2)时间和空间语义
时间消耗和存储空间
同步方式的考虑
3.6.3 选择关系
1) 迪米特法则
类的方法不应该以任何方式依赖于任何类的结构,除了它自己累的当前(顶层)结构之外。而且,每个方法只能够对一个非常有限的类集的对象发出消息。
迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle简写LKP) talk only to your immediate friends 还有如下一些关于应用迪米特法则的注意事项: 迪米特法则不希望类直接建立直接的接触。如果真的有需要建立联系,也希望能通过它的友元类来转达。因此,应用迪米特法则有可能造成的一个后果就是:系统中存在大量的中介类,这些类之所以存在完全是为了传递类之间的相互调用关系——这在一定程度上增加了系统的复杂度。 |
2) 机制和可见性
如何协作?谁和谁需要可见?
3.6.4 选择实现
外部视图稳定下来后,才转向内部视图。
为类和对象选择表示形式,以及将类和对象放入一个模块。
表示形式的例:圆锥类的体积方法,是存储体积变量,还是每次调用时计算
打包:在模块中声明类和对象。可见性和信息隐藏