无论是计算机科班还是半路出家,只要稍微系统地学习过计算机语言,就不可能没听过“面向对象编程”这个概念,英文缩写就是OOP,即 噢!原*!呃不是串台了。OP就是Object-Oriented Programming。本文将会以我的理解介绍一下什么是“面向对象”的思维模式。若有不严谨不恰当之处,恳请读者批评指正。
面向过程
我们先来聊聊另一种思维方式——面向过程。不知道大家对做数学、物理等题目还有无印象,这个过程我认为是非常典型的面向过程,尤其是做物理题目的时候。按照题目已知数据,按照一定的顺序一步步列出公式,公式后面还标有①、②、③......最后代入数据得到答案。这就是面向过程,非常关注做什么、怎么做。
相信大家初学变成时大多从面向过程的思维方式开始,明确了面向过程后,我们接着聊面向对象,大家可以自己体会一下它们的区别。下面从面向对象的几大重要特性为大家介绍。
封装
再举一个例子,最近笔者自己装了一台机子。我的目标是点亮它(即成功开机),那么从购买电脑所需的CPU、主板、显卡等配件,到一步步地将U装到板子上、装内存条、装风扇、显卡、接线等等,到最后成功点亮——这就是装机的过程,同时也是用面向过程的角度去看待这个机器。
但如果从面向对象的角度呢?我只关注它是什么,我看到的只是一个箱子,里面的配件我一点也看不到(不许说你用海景房)、我也不关心。它是一台电脑主机,它有开机键、重启键、有几个USB接口、HDMI/DP接口等,我可以开机、重启,也可以用它提供的接口。
但你要问它里面有啥,接口内部是怎么实现的、开机是怎么实现的?对不起无可奉告。体现在伪码中就是下面的Computer类里的...,这是具体的实现,但外部防伪码时是不可见的,包括伪码中的PRIVATE关键字,亦表示对外部来说不可见。就像是别人问你工资多少,你不想告诉他还会把别人骂一顿(就是程序报错了)。
CLASS Computer
// 属性
PRIVATE isPoweredOn = FALSE
PRIVATE usbPortCount = 4 // 假设有4个USB接口
PRIVATE usedUsbPorts = 0 // 当前使用的USB接口数
PRIVATE hdmiPortCount = 1 // 假设有1个HDMI接口
PRIVATE dpPortCount = 1 // 假设有1个DP接口
PRIVATE usedHdmiPorts = 0 // 当前使用的HDMI接口数
PRIVATE usedDpPorts = 0 // 当前使用的DP接口数
// 方法:开机
METHOD powerOn()
...
END METHOD
// 方法:重启
METHOD restart()
...
END METHOD
// 方法:连接USB设备
METHOD connectUsbDevice()
...
END METHOD
// 方法:断开USB设备
METHOD disconnectUsbDevice()
...
END METHOD
// 方法:连接HDMI显示器
METHOD connectHdmiDisplay()
...
END METHOD
// 方法:连接DP显示器
METHOD connectDpDisplay()
...
END METHOD
// 方法:获取当前状态
METHOD getStatus()
...
END METHOD
END CLASS
电脑机箱的例子体现了面向对象中一个很重要的特性:封装。
- 封装
● “装”:我将组成电脑的必要配件都给装一起了,使其能成为一台完整的电脑自助机;
● “封”:我最后盖上机箱盖子把里面的配件以及它们之间的关联都给遮起来了。
抽象
现在大家假设自己有神力,能够将一台电脑的配件复制并移植到笔记本、台式机,甚至超级计算机。现在你的目的是以最快的速度生产出这三种类型的电脑。最聪明的办法当然是运用你的神力,而不是每种电脑都重新再配一遍。
而面向对象的思维就有这种“神力”。三种类型的电脑都有一些共同的属性和方法。同时,它们也有区别。我们需要给三种类型的电脑自己发挥的空间,总不能超算的算力和笔记本一样。
这个时候,我们更像是发布了一个标准化图纸,我们说明一台电脑应该有USB接口、HDMI接口,同时要能开机、要能重启、要能表明电脑类型等。但具体有多少个USB接口、具体的电脑类型是什么或是有什么其他的方法(比如:笔记本可以有触摸屏、超算可以高性能计算等),我们给予具体类型自己发挥的空间。
ABSTRACT CLASS Computer
// 属性
PROTECTED isPoweredOn = FALSE
PROTECTED usbPortCount = 2 // 默认2个USB接口
PROTECTED usedUsbPorts = 0
PROTECTED hdmiPortCount = 1 // 默认1个HDMI接口
PROTECTED usedHdmiPorts = 0
PROTECTED dpPortCount = 0 // 默认0个DP接口
PROTECTED usedDpPorts = 0
// 方法:开机
METHOD powerOn()
...
END METHOD
// 方法:重启
METHOD restart()
...
END METHOD
// 方法:连接USB设备
METHOD connectUsbDevice()
...
END METHOD
// 方法:连接HDMI显示器
METHOD connectHdmiDisplay()
...
END METHOD
// 抽象方法:子类实现
ABSTRACT METHOD getType()
END METHOD
// 方法:获取状态
METHOD getStatus()
...
END METHOD
END CLASS
以上伪码就是抽象的过程,总体上与上一段伪码没什么区别,只是多了ABSTRACT关键字和抽象方法getType。大家可以发现getType这个方法没有...意味着它本身就未实现,由谁来实现呢,当然是具体类型的电脑去实现,当然不同类型计算机开机、重启、连接USB设备的方法也可能不同,所以也可以让它们变成抽象方法,留着给具体类型发挥。
抽象完之后,很显然这台电脑还用不了,ABSTRACT关键字说明了一切,上文说到这就是标准化图纸,总不能拿着图纸就启动吧。我们接着往下。
继承
我们已经有了图纸,接下来各种类型的电脑按照统一的图纸去制作,这个过程就叫做“继承”。
CLASS Laptop INHERITS Computer
// 额外属性
PRIVATE batteryLevel = 100 // 电池电量(百分比)
PRIVATE hasTouchScreen = FALSE
// 构造函数
CONSTRUCTOR()
usbPortCount = 3 // 笔记本通常有3个USB接口
hdmiPortCount = 1
dpPortCount = 1
END CONSTRUCTOR
// 实现抽象方法
METHOD getType()
RETURN "Laptop"
END METHOD
// 特有方法:设置是否为触摸屏
METHOD setTouchScreen(isTouch)
...
END METHOD
// 特有方法:检查电池
METHOD checkBattery()
OUTPUT "Battery level: " + batteryLevel + "%"
END METHOD
END CLASS
可以看到,上面的伪码用到了INHERITS(即继承的意思)。Laptop笔记本“继承了”Computer,也就是按照我们上述的图纸开始组装笔记本,笔记本被认为USB接口较少,而且可以有触摸屏。也是在笔记本里实现了“图纸”中的抽象方法getType。它还“自我发挥”地添加了一些笔记本特有的属性和方法。
那么另外两种类型也是类似地“按照图纸组装”并扩展特有的功能。下面也给出伪码。大家选择性参考。
CLASS SuperComputer INHERITS Computer
// 额外属性
PRIVATE processingPower = 1000 // 假设单位为TFLOPS
// 构造函数
CONSTRUCTOR()
usbPortCount = 8 // 超级计算机有更多接口
hdmiPortCount = 0 // 通常无HDMI
dpPortCount = 0 // 通常无DP
END CONSTRUCTOR
// 实现抽象方法
METHOD getType()
RETURN "SuperComputer"
END METHOD
// 特有方法:运行高性能计算
METHOD runHighPerformanceTask()
IF isPoweredOn THEN
OUTPUT "Running high-performance task with " + processingPower + " TFLOPS."
ELSE
OUTPUT "Cannot run task. SuperComputer is off."
END IF
END METHOD
END CLASS
CLASS Desktop INHERITS Computer
// 额外属性
PRIVATE hasRgbLighting = FALSE // 是否有RGB灯效
// 构造函数
CONSTRUCTOR()
usbPortCount = 6 // 台式机通常有较多USB接口
hdmiPortCount = 2
dpPortCount = 2
END CONSTRUCTOR
// 实现抽象方法
METHOD getType()
RETURN "Desktop"
END METHOD
// 特有方法:设置RGB灯效
METHOD setRgbLighting(isEnabled)
hasRgbLighting = isEnabled
OUTPUT "RGB lighting set to: " + (IF hasRgbLighting THEN "On" ELSE "Off")
END METHOD
END CLASS
多态
上文提到,getType方法在基类(也就是“图纸”)中并未实现,由后续的子类(即具体类型的电脑)自行实现。同一个方法在不同类型的电脑中却对应着不同的实现方式,在面向对象中,这就是多态性。
结语
(AI总结)本文通过对比面向过程和面向对象的思维方式,深入浅出地介绍了面向对象编程(OOP)的核心概念及其四大特性:封装、抽象、继承和多态。
面向过程 vs. 面向对象:面向过程关注“做什么”和“怎么做”,以步骤和流程为核心,例如物理题的解题过程。而面向对象更关注“是什么”,通过对象来组织和操作数据,注重系统的模块化和可扩展性。
封装:以电脑机箱为例,封装是将内部实现细节隐藏,只暴露必要接口(如开机键、USB接口等),保护数据并降低外部依赖。
抽象:通过定义一个通用的“电脑”蓝图(抽象类),规定了必要属性和方法,允许不同类型电脑(如笔记本、超级计算机)根据需要具体实现。
继承:具体类型的电脑(如笔记本、台式机、超级计算机)基于抽象蓝图扩展功能,继承通用特性并添加特有属性和方法。
多态:通过抽象方法(如getType)在不同子类中实现不同行为,体现了同一接口、不同实现的灵活性。
通过这些特性,面向对象编程提供了一种更模块化、可维护和可扩展的编程方式,广泛应用于现代软件开发中。