面向过程(Procedural)

思路:按步骤组织代码。把复杂任务拆成一系列函数,依次调用。

核心关注:做什么(步骤)。

读取数据 → 处理数据 → 输出结果

适合:简单、线性的任务;脚本;性能敏感的场景。

C 语言是典型的面向过程语言(虽然也能实现类似对象的结构)。

面向对象(OOP)

思路:把程序看作对象的集合。每个对象有自己的数据(属性)和行为(方法)。

核心关注:谁来做(对象)。

四大特性:

一、封装(Encapsulation)

把数据和操作数据的方法打包在一起,并控制外部访问的权限。

目的:隐藏实现细节,只暴露必要的接口。

二、继承(Inheritance)

子类继承父类的属性和方法,可以复用和扩展。

目的:代码复用。

风险:过深的继承层次会导致代码难以理解和维护("脆弱基类问题")。

三、多态(Polymorphism)

同一个接口,不同的实现。

目的:调用方不需要知道具体类型,只依赖抽象接口——降低耦合。

四、抽象(Abstraction)

提取本质特征,忽略细节。

对比

面向过程面向对象
组织单位函数/步骤对象/类
数据与行为分离绑定在一起
适合简单、线性任务复杂、状态多的系统
复用方式函数调用继承、组合、多态

一个重要的现代观点

"组合优于继承"(Composition over Inheritance)

GoF 设计模式中提出的原则:优先使用组合(把对象作为另一个对象的成员),而非继承。

为什么:

  • 继承是一种强耦合关系——子类依赖父类的实现细节;
  • 继承层次一旦设计错误,修改成本很高;
  • 组合更灵活,可以在运行时改变行为(如策略模式)。

继承适合"is-a"关系(猫是一种动物),组合适合"has-a"关系(车有引擎)。

误用继承是 OOP 中最常见的问题之一——用继承来复用代码,而不是表达真实的分类关系。

现代语言的态度

纯 OOP 语言(如 Java)要求一切都是类——这在某些情况下显得笨重(如只有静态方法的工具类)。

现代趋势是多范式融合:

  • Python/JavaScript/Rust/Go:支持多种范式,不强制 OOP;
  • 函数式编程的影响在增强(不可变数据、纯函数、高阶函数);
  • Go 语言干脆没有类和继承,用组合和接口实现多态。

什么时候用什么

简单的脚本、数据处理流程:用面向过程(甚至函数式风格)更直接。

复杂的、状态多、需要长期维护的业务系统:对象提供了有效的组织方式——把相关的状态和行为放在一起,符合人类的认知习惯。

关键:不要教条。 一个系统里可以同时使用多种范式——用对象组织领域模型,用函数处理数据转换,这很常见。

一个实用判断

如果你发现一个类里只有方法、没有状态(或只有静态方法),那它可能是"伪装成类的函数"。

反之,如果你发现一组数据总是被同样的几个函数一起操作——那它们可能应该封装成一个对象。

说明:本文为编程范式的知识整理。