用大白话聊聊,什么是面向对象
想象一下,咱们要盖一座房子,不是一座,是很多很多座,还要有不同样式的,比如四合院、小洋楼、摩天大厦。
要是您是一个刚入行的工匠,您可能会这么想:先打地基,然后砌墙,再上梁,最后封顶、您会写一本厚厚的施工手册,里面密密麻麻记录着每一步操作:“第一步,挖土三米深;第二步,浇筑混凝土……” 这就是一份指令清单、盖四合院用这本手册,盖小洋楼也用这本,只不过到了某些步骤要做修改、工程小还行,一旦复杂起来,比如盖一座摩天大厦,这本手册可能会变得比大厦本身还复杂,改一处牵动全身,简直是噩梦。
这种“指令清单”式的思维,在编程的世界里,咱们称之为“面向过程”、它关注的是“怎么做”,一步一步地执行。
后来,一位聪明的总设计师觉得这样太累了、他说:“我们别总想着具体的一砖一瓦怎么砌、我们换个思路,这个世界是由各种‘东西’组成的、” 房子项目里有什么东西?有“柱子”、有“墙壁”、有“窗户”、有“门”。
这位设计师首先做了一件事:他为每一种“东西”都画了一张标准图纸。
蓝图与实体:类和对象
这张图纸,就是“类”(Class)。
比如,他画了一张名为《标准门设计图》的蓝图、这张图纸上规定了,但凡是“门”,就必须有以下特征(属性):
颜色
材质(木头还是钢铁)
高度
宽度
它也必须具备以下功能(方法):
可以被打开
可以被关闭
可以被上锁
这张图纸本身不是一扇真正的门,它只是一个定义,一个标准、有了这张图纸,工厂里的工匠们就能根据它,造出成千上万扇真正的、摸得着的门。
这些被制造出来的、独一无二的实体门,就是“对象”(Object)。
比如,张三家的大门是一个对象:红色的、木质的、两米高、李四家的房门也是一个对象:白色的、复合材料的、一米九高、它们都源自《标准门设计图》这个“类”,所以它们都有门的属性和功能,但各自的具体情况又不一样。
“面向对象”的核心思想,就是把世界看作是由无数个这样的“对象”组成的、编程不再是写死板的指令清单,而是先设计好各种“东西”的图纸(类),然后根据图纸造出实体(对象),再让这些对象互相沟通、协作来完成任务。
自己的事自己管:封装

现在我们有了“门”这个对象、作为房子的主人,您需要开门时,您会怎么做?您会走到门前,转动门把手、门就开了。
您需要关心门锁内部的弹簧是怎么运作的吗?您需要了解门轴的摩擦系数吗?完全不需要、门把手和门锁,就是这扇门提供给您操作的“接口”、门内部的复杂结构和工作原理,全都被隐藏在门板后面了。
这种“把内部细节藏起来,只对外提供操作接口”的做法,就叫“封装”(Encapsulation)。
它的好处显而易见、第一,安全、您不会因为误操作,把门锁里的弹簧给弄坏了、第二,省心、您只需要知道“转动把手”这个动作就行,门的内部构造就算升级换代了,从弹簧锁换成了电子锁,只要开门的方式还是“转动把手”或“按一下按钮”,您的使用习惯就完全不受影响。
在编程里,封装让代码模块化,每个对象都像一个功能完善的黑盒子,我们用它,但不必深究其内部原理,让系统变得更简单、更可靠。
龙生龙,凤生凤:继承
总设计师画好了《标准门设计图》、现在,业主需要一扇“防盗门”。
防盗门是不是一种门?是的、它具备门的一切基本属性和功能(颜色、材质、能开关、能上锁)、但它又比普通门更特殊,它可能需要有“警报”功能和更坚固的“锁芯等级”属性。
设计师没必要从零开始重新画一张《防盗门设计图》、他拿过《标准门设计图》作为基础,然后在这上面补充新的内容、他声明:《防盗门设计图》继承自《标准门设计图》。
这样一来,《防盗门设计图》自动拥有了《标准门设计图》里定义的所有属性和功能,设计师只需要在上面添加两项新内容:
新增属性:锁芯等级
新增功能:触发警报
这种“基于一张现有图纸,创造一张更具体、更强大的新图纸”的行为,就是“继承”(Inheritance)。
继承极大地提高了效率,避免了重复劳动、它还建立起一种清晰的层级关系,比如我们可以有“门”类,下面派生出“木门”类、“铁门”类、“防盗门”类、整个体系井井有条,易于管理和扩展。
各显神通:多态
项目进入了后期,需要对所有安装好的部件进行测试、测试员接到一个指令:“把所有能‘打开’的东西都打开一遍、”
测试员走到一扇门前,他知道这是个“门”对象,他执行“打开”操作,门开了。
他又走到一扇窗户前,这也是一个能“打开”的东西,他执行“打开”操作,窗户被推开了。
他还看到一个抽屉,同样能“打开”,他执行“打开”操作,抽屉被拉开了。
您看,“打开”这个指令是同一个,但用在“门”、“窗户”、“抽屉”这些不同的对象上时,它们各自的实现方式(门是转动,窗户是平推,抽屉是拉出)是完全不同的。
这种“同一个指令,作用于不同对象,产生不同行为”的现象,就是“多态”(Polymorphism)。
多态让我们的指令变得更加通用和抽象、测试员不需要为每一种东西都准备一个专门的指令,比如“转开门”、“推开窗”、“拉开抽屉”、他只需要下达一个统一的“打开”指令,至于具体怎么打开,由那个对象自己去决定、这让程序具有了惊人的灵活性和可扩展性、假如未来我们又发明了一种新的能打开的东西,比如“保险箱”,只要它也懂得如何响应“打开”这个指令,测试员的测试流程就无需任何改动。
面向对象,本质上是一种思考和组织代码的方式、它通过模拟现实世界中“万物皆对象”的理念,利用封装、继承和多态这三大法宝,帮助我们构建出结构清晰、易于维护、能够从容应对复杂变化的大型软件系统、它不是一堆冰冷的代码,而是一种更接近人类思维方式的、充满智慧的工程哲学。