软件设计

什么是面向对象编程(OOP)?它与面向过程有什么不同?

学习编程时,你一定会遇到这个词。

4 分钟阅读
什么是面向对象编程(OOP)?它与面向过程有什么不同? 封面图

什么是面向对象编程(OOP)?它与面向过程有什么不同?

学习编程时,你一定会遇到这个词。

“这段代码应该用面向对象的方式编写。”

第一次听到时,确实会让人感到困惑。面向过程是什么?面向对象到底有什么不同?一时很难理解。

先说结论:面向过程关注“要按什么顺序做什么”,而面向对象更强调“谁来负责这件事”。区别在于,是否把数据和处理这些数据的功能放在一起。

本文会用点咖啡的例子,轻松讲解两者的区别,并展示它们在实际代码中的不同。


面向过程编程就像一份烹饪食谱

面向过程顾名思义,关注的是“过程”,也就是顺序。

数据和处理数据的函数彼此分开,程序按照顺序从上到下执行。

想想烹饪食谱就很贴切:清洗、切碎、翻炒,再装盘。把这个顺序原样写进代码,就是面向过程编程。

来看一个简单的账户示例。

var balance = 10000  // 数据

func deposit(amount: Int) {   // 功能分开
    balance += amount
}

deposit(amount: 5000)
print(balance)
// 输出: 15000

balance 数据暴露在外部,deposit 函数会直接修改它。

对于小型程序,这反而更简单、更快。问题会在程序变大时出现。

当账户增加到100个,修改余额的函数又散落各处时,要追踪数值在哪里发生变化会非常困难。


什么是面向对象编程(OOP)?

面向对象会把数据和功能组合成一个整体,这个整体称为“对象”。

以账户为例,就是把“余额”数据和“存款”功能组合成一个单元。

把刚才的账户改成对象来看看。

class Account {
    private var balance = 10000   // 将数据隐藏在内部

    func deposit(_ amount: Int) { // 功能也放在一起
        balance += amount
    }
    func show() { print(balance) }
}

let myAccount = Account()
myAccount.deposit(5000)
myAccount.show()
// 输出: 15000

balance 现在被隐藏为 private。外部不能再随意修改余额,只能通过 deposit 等规定的入口访问。

这就是面向对象的核心:保护数据,并明确“谁负责这件事”。

用点咖啡来比喻:面向过程是自己磨咖啡豆、烧水,什么都自己做;面向对象则是交给别人,说一句“咖啡师,请来一杯美式”。怎么制作,由咖啡师对象自行负责。


OOP 的4个核心特征

面向对象有四根支柱。术语看起来很难,但概念其实很简单。

  • 封装:隐藏数据,只允许通过规定的入口访问(就像上面的 private)
  • 继承:继承现有类的功能并重复利用
  • 多态:相同的命令对不同对象产生不同的行为
  • 抽象:隐藏复杂的内部细节,只暴露必要内容

多态尤其强大。让它“叫一声”时,狗会汪汪叫,猫会喵喵叫。命令只有一个,但每个对象会自动做出不同的响应。

一个 Account 对象同时负责余额和存款
一个 Account 对象同时负责余额和存款

什么时候使用面向对象,什么时候面向过程更合适

面向对象并不总是正确答案,要根据情况选择。

情况 适合的方式
短脚本、一次性计算 面向过程
数据流简单且按顺序执行 面向过程
规模较大且持续增长的项目 面向对象
多人协作开发的代码 面向对象
相似概念反复出现 面向对象

规模小且简单时,面向过程反而更简洁;如果代码规模大、复杂且需要长期维护,面向对象就能发挥优势。

规模小时按顺序处理,变大变复杂后按责任拆分更方便
规模小时按顺序处理,变大变复杂后按责任拆分更方便

面向过程设计顺序,面向对象设计责任。

面试时会这样问

问:面向过程和面向对象最大的区别是什么? 答:数据与功能的关系。面向过程将数据和函数分开,围绕顺序执行;面向对象则把两者组合成对象,按责任单元管理。因此,规模越大,越有利于维护和协作。

问:为什么封装很重要? 答:它能阻止外部直接修改数据,减少意外变更。由于只能通过规定的方法访问,因此更容易追踪错误;即使修改内部实现,也较少影响外部代码。


即使术语听起来很宏大,核心其实只有一个问题:“该如何处理数据?”

从小段代码开始练习将其组合成对象,很快就能掌握要领。希望你能用今天学到的内容,重构自己代码中的一小部分。

延伸阅读