第一章 对象的概念
抽象
Alan Kay 总结了对象的五大基本特征
- 万物皆对象。
- 程序是一组对象,通过消息传递来告知彼此该做什么。
- 每个对象都有自己的存储空间,可容纳其他对象。
- 每个对象都有一种类型。
- 同一类所有对象都能接收相同的消息。
服务提供
在良好的面向对象设计中,每个对象功能单一且高效。这样的程序设计可以提高我们代码的复用性,同时也方便别人阅读和理解我们的代码。只有让人知道你提供什么服务,别人才能更好地将其应用到其他模块或程序中。
封装
我们可以把编程的侧重领域划分为研发和应用。
使用访问控制的原因有以下2点:
- 让应用程序员不要触摸他们不应该触摸的部分。(请注意,这也是一个哲学决策。部分编程语言认为如果程序员有需要,则应该让他们访问细节部分。);
- 使类库的创建者(研发程序员)在不影响后者使用的情况下完善更新工具库。例如,我们开发了一个功能简单的工具类,后来发现可以通过优化代码来提高执行速度。假如工具类的接口和实现部分明确分开并受到保护,那我们就可以轻松地完成改造。
继承
"是一个"与"像是一个"的关系
对于继承可能会引发争论:继承应该只覆盖基类的方法(不应该添加基类中没有的方法)吗?如果这样的话,基类和派生类就是相同的类型了,因为它们具有相同的接口。这会造成,你可以用一个派生类对象完全替代基类对象,这叫作"纯粹替代",也经常被称作"替代原则"。
多态
通过派生新的子类来扩展设计的这种能力是封装变化的基本方法之一。
这就是关键所在:当程序接收这种消息时,程序员并不想知道哪段代码会被执行。“绘图”的方法可以平等地应用到每种可能的“形状”上,形状会依据自身的具体类型执行恰当的代码。
通过继承,程序直到运行时才能确定代码的地址,因此发送消息给对象时,还需要其他一些方案。为了解决这个问题,面向对象语言使用后期绑定的概念。当向对象发送信息时,被调用的代码直到运行时才确定。编译器确保方法存在,并对参数和返回值执行类型检查,但是它不知道要执行的确切代码。
在某些语言中,必须显式地授予方法后期绑定属性的灵活性。在 Java 中,动态绑定是默认行为,不需要额外的关键字来实现多态性。
把子类当成其基类来处理的过程叫做“向上转型”(upcasting)。
发送消息给对象时,如果程序不知道接收的具体类型是什么,但最终执行是正确的,这就是对象的“多态性”(Polymorphism)。面向对象的程序设计语言是通过“动态绑定”的方式来实现对象的多态性的。编译器和运行时系统会负责对所有细节的控制;我们只需知道要做什么,以及如何利用多态性来更好地设计程序。