面向对象编程——OO思想
在面向对象编程时,另一种方式是告诉司机,"请载我去机场"。尽管具体实现在广州、北京或上海等不同城市中是不同的,但在任何城市都可以这么说。因为司机知道怎么去机场,司机对自己的行为负责,并信任司机知道如何执行,这就是职责转移,显然这种方法比功能分解法要容易得多。
由于每个对象都对自己的行为负责,因此必须有方法告诉对象要做什么。而方法都被标识为能够被其它对象调用,这些方法的集合被称为对象的公开接口。其形象的比喻为,"将软件对象看成具有某种职责的人,他要与其他人协作完成工作。"
>>> 4.1.2 OO机制
面向对象的编程是由类(class)这种结构实现的,C++类的概念是对C结构概念扩展。因此表面上看起来这些特征与面向对象编程语言有很大的关联,但实际上能用任何一种语言实现。不管实现语言如何,任何大的软件系统都会以某种形式使用抽象、继承或多态性。
1、封装
封装是OO方法中的一个重要原则,其含义是将封装视为任何形式的隐藏,对外形成一个边界,只暴露有限的对外接口使之与外部发生联系。封装不仅仅是将对象的全部属性和全部操作结合在一起,形成一个不可分割的独立单位(对象),而是发现变化将其封装。
抽象实现封装的分析工具,抽象可以使我们专注于应用程序最本质的方面,同时忽略细节。在确定如何实现功能之前,先关注对象是什么?做了什么?更具体地,抽象是将一类对象的共同特征总结出来创建类的过程,包括数据抽象和行为抽象。
数据抽象是数据和处理方法的结合,即封装数据和函数到类中的能力,因此又将数据抽象称为信息隐藏或封装,信息隐藏是一种软件设计思想。由于不必知道内部结构,因此可以将数据当作黑盒子来操作。即使将来数据结构发生变化,对外部也没有影响。从而避免程序的各个组成部分过于相互依赖,否则很小的变化也会引起巨大的连锁反应。
在结构化的设计中,通常将代码封装到函数和模块中。因此封装不是OO语言所特有的,但它能将数据结构和行为组织在一个实体中,其主要目的是为使用代码的程序员提供一致的接口,这是面向对象编程的突出特点。尽管如此,面向对象和结构化的代码并不是互斥的,实际上不用结构化代码将无法创建对象。因此在构建面向对象的系统时,在设计中依然离不开结构化的技术。
2、继承
虽然结构化程序设计通过编写一个功能块实现重用,但面向对象程序设计实现代码重用的方法是允许定义类之间的关系。而继承是实现该功能的主要手段,其将不同代码中相同的部分提取出来。即抽取不同类的共同属性和行为创建全新的类,实现代码最大限度地重用。
利用类和继承这两个特性,高效地将抽象数据通过类封装起来,即通过类将同一类对象管理起来。因此可以说类是将数据黑盒子化的工具,而继承可以从其它类继承属性,只需要扩展实现或对实现稍作改进,即可支持软件重用。
在经典的Shape(形状)示例中,Circle(圆形)、Square(矩形)和Star(星形)都直接继承自Shape,这种关系通常被称为is-a关系。因为圆是一种形状,矩形也是一种形状,星形也是一种形状,即Circle、Square和Star都是Shape的扩展。当子类继承自父类时,任何父类能做的事情子类都可以做。
3、多态性
当你要求某人画一个形状Shape时,实际上没有人能完成这个任务。因为形状是一个抽象的概念,所以Shape无法提供绘制代码,必须指定一个具体的形状。有了具体形状,就可以为各种具体形状实现各自的绘图代码。
显然,无论画什么形状,其共性是Draw画图方法,每种形状都可以通过函数指针调用各自的绘图代码绘制自己,这就是多态的意义,即多态允许用相同的方法(代码)在运行中,根据对象的类型调用不同的处理函数。
4、组合
组合是指在类中包含一个对象,且该对象是其它类的实例,开发者将责任委托给所包含的对象完成。组合有两种方式:聚合和组合,这些方式表示了对象之间的协作关系。
聚合就是"可聚可散"的意思,被包含的对象如同一个集合。聚合关系是整体与部分的关系,且部分可以离开整体而单独存在。虽然汽车和发动机是整体和部分的关系,但发动机离开汽车仍然可以存在,所以汽车和发动机是聚合关系。
虽然组合关系也是某种形式的整体和部分的聚合,但部分不能离开整体而单独存在,部分对象与整体对象之间具有同生共死的关系。在组合关系中,部分是整体的一部分,且整体可以控制部分的生命周期,即部分的存在依赖于整体。
虽然花瓣不是一种花,但它是花的一部分,因此它们之间存在一种真正的has-a组合