[OOP]C++面向对象高效编程 Chapter 1
什么是面向对象编程
1 理解对象模型
OOP中的基本实体是类。对象是类的实例。
在OOP中,函数通过对象调用。
2 理解消息、方法和实例变量
类的任何用户(另一个程序、另一个类等)都是类的客户。客户通过类的对象使用成员函数(消息)进行有用的操作。
消息只是客户所见的一个名称,该名称可能在运行期被绑定在正确的实现上(方法)。类的每个示例都包含实例变量的单独副本。
3 什么可以作为类
类拥有一组对象的共同属性(或者特性)。
类不只是容器,不能认为它仅仅用于存储被函数修改的数据。类为客户提供了复杂实体的简化版本,并允许客户通过操作类的对象完成有用的工作。类不只是将它的各个部分简单地组合起来而已。类决定如何完成任务,它清楚地陈述了该类的对象可以做什么。
4 什么不是类
一个 C“结构”不能直接成为一个类。不能将结构修改成类,让所有数据成为私有数据,然后添加一组函数来获得和设置数据成员,这不是类。类不只是一组允许客户获取和设置数据成员值的函数。数据封装隐藏了类中的数据,而且通过成员函数提供更高层次的抽象。如果只是让函数读写结构中的数据,其实并未简化任何东西。只包含获值函数(getter)和设值函数(setter)的类是糟糕的设计。
5 类的目的
设计类的目的必须非常明确。一个优秀的类应该易于理解和使用,必须清楚地向客户说明其目的。每个类都是为特定领域的某种用途而设计的。
类(实际上是类的对象)负责履行其功能。当设计出类后,它(实际上是类的设计人员)便对客户承诺了它的功能。程序在执行时,类会负责管理一些细节,因此客户不用担心。
6 深入了解对象
区别类和对象是一个逻辑问题。简单地说,对象是带有状态和行为的活的实体。所有类对象的行为都定义在类中,而状态则由对象单独维护。
6.1 对象的状态
每个BankAccount类对象中都有一个balance数据成员。假设我们不允许客户的账户透支,那么,只需声明账户中的余额不允许小于0。这是任何银行账户对象的已知性质(property),我们不必检查对象的状态来确认这个属性。也就是说,这是每个银行账户对象的静态性质(static property)。然而,在BankAccout类对象生存期内的任何时候,账户中的余额都是balance数据成员中的值。该数据成员的值随着账户的存款、转账、取款不断变化。因此,账户余额是一个动态变化的值。换言之,balance 数据成员是一个动态值。对象的状态是所有静态性质以及这些静态性质的动态值的集合。
6.2 对象状态的重要性
对象如何响应我们的命令(操作)以及对其他对象(客户)做什么,都直接依赖于对象的状态;执行某方法所得的结果也直接依赖于对象的状态。
6.3 谁控制对象的状态
对象的状态通过成员函数修改。类假定无法从外部修改对象的状态。所有不让普通客户访问的数据都应封装在类的private区域中。这也称为数据封装(data encapsulation)。
6.4 对象的行为
对象的行为在某种方式上是对客户调用消息的响应。行为是对象对消息采取的行动和做出的反应。消息会引起状态的变化,也会引起发送更多的消息至其他对象,或两者兼有之。
7 面向对象软件开发的阶段
7.1 面向对象分析OOA
从简单描述问题开始(大多数都不完整),这是面向对象软件开发过程的起点。在这一阶段中,我们要找到合适的类。
面向对象分析(Object-Oriented Analysis,缩写OOA)涉及从类和对象的角度分析问题,这些类和对象都要从问题领域(problem domain)中找出。但是,这些类并不是在最终实现中能直接使用的类。整个过程基本上是一个建模练习,即尝试建立问题领域的模型。本阶段的任务主要是,彻底地分析问题和明确地指定要求。要在客户的问题领域找出类和对象,并用其完整地描述什么方案可行,什么方案不可行。换言之,我们应采用客户能够理解的类和对象来描述问题。这些类和对象都可以直接在问题领域中找到。
在OOA阶段中,我们应该将注意力放在问题领域中使用的类,而非实现中使用的类。实现的细节将在面向对象设计(OOD)阶段实现。
7.2 面向对象设计OOD
OOD(面向对象设计)阶段在OOA(面向对象分析)阶段之后,在本阶段中,我们将在OOA阶段开发的框架中加入细节,待解决的问题将被分解为类和对象用于实现中。本阶段需要完成的任务包括定义类之间的关系、描述对象如何才能适应系统的进程模型、如何跨地址空间划分对象、系统如何完成动态行为等。
找到那些难以琢磨的对象
一般情况下,可将问题中的下列实体转化为类:
- 人,位置和东西;
- 事件——鼠标输入、出生、死亡等;
- 交易——同意贷款、汽车销售等;
- 人所扮演的角色——父亲、母亲等。
7.3 面向对象编程OOP
这是面向对象软件开发环节的最后一个阶段。将 OOD 阶段的成果输出,将其输入至OOP 阶段中。
8 对象模型的关键要素
建立对象模型的关键要素:
- 数据抽象
- 封装
- 层次
数据抽象(data abstraction)是为了强调对象的相似性,忽略其差异性来定义类。在表现类(抽象)的主要特性时,应避免展现那些不重要的和分散注意力的元素。实际上,类就是一个抽象。顺带一提,抽象将重点放在对象的外部视图上,并将对象必不可少的行为从内部的实现细节中分离出来。
封装(encapsulation)是为了隐藏抽象的内部实现细节。它将抽象的外部接口从内部实现细节中分离出来。封装和抽象彼此互补。一个设计良好的抽象会封装一些成员,而被封装的实体则帮助抽象保持完整性。需要注意的是:抽象先于封装。另外,只有在开始实现时,才应该将注意力放在封装上。
层次(hierarchy)是为了支持抽象的有序。抽象很强大很有用。但是,在绝大多数重大问题中,我们最终都会由于创建了太多的抽象,以至于无法统观大局。虽然封装和模块在一定程度上能缓解这一局面,但是,我们仍陷入了不计其数的抽象迷雾中。人的思维一次只能理解一组有限的抽象,提出太多抽象对读者而言简直就是一次信息保留测试,实在让人难以消化。为了避免这些不利因素,我们可以将这些抽象安排在不同的层次,这样即便尚未充分理解抽象的主要特性,也可完全明白某层次中的所有抽象。
在OOP中普遍存在两种层次。继承关系支持类层次(class hierarchy)(is-a关系,见图1-6);聚集关系(aggregation relation)(has-a关系,见图1-7)支持部分-整体概念。继承用于描述一般-特殊关系,而聚集用于描述涉及包含(containment)和共享的关系。