编程范式总览
编程范式指的是结构化编程、面向对象编程以及函数式编程。
结构化编程是第一个普遍被采用的编程范式,我们可以将结构化编程范式归结为一句话:结构化编程对程序控制权的直接转移进行了限制和规范
面向对象编程是编程领域中第二个被广泛采纳的编程范式,我们也可以用一句话来总结面向对象编程:面向对象编程对程序控制权的间接转移进行了限制和规范。
函数式编程是近些年刚刚被采用的,我们在这里可以将函数式编程范式总结为这句话:函数式编程对程序中的赋值进行了限制和规范。
这三种编程范式都是从某一方面限制和规范了程序员的能力,没有一个范式是增加新能力的,也就是说,每个编程范式的目的都是设置限制。这些范式主要是为了告诉我们不能做什么,而不是可以做什么。
其实新范式不是否定旧的范式,而是在其约束的基础上叠加新约束。
每种范式都通过"限制"来管理复杂性
结构化编程
结构化编程对程序控制权的直接转移进行了限制和规范,这句话的意思是指结构化编程将原本自由混乱的指令跳转(goto)规范为了顺序、分支、循环三种基本结构,从而提升代码的可读性以及可维护性。限制控制权的直接转移,不是剥夺能力,而是引导代码走向可维护性
这里的直接转移是什么意思呢,指的是控制权的转移由代码直接硬编码,调用方与被调用方关系明确固定,无须通过中间机制,直接通过函数名或者地址跳转。
结构化编程示例
bash
print("begin")
if x > 0:
print("go123")
else:
print("go456")
print("end")
面向对象编程
面向对象编程对程序控制权的间接转移进行了限制和规范,这句话的意思是面向对象编程通过封装、继承、多态三大特性,对程序控制权加以限制和规范。
那么是如何进行限制和规范的呢,主要是通过以下3点:
- 禁止外部代码直接访问对象内部数据或方法,控制权必须通过对象的公有方法(接口间接转移)
- 禁止随意复用代码,必须通过类继承层次结构,子类只能通过重写父类方法(
@Override
)或调用父类方法(super()
)来扩展/修改行为。 - 禁止直接依赖具体实现,必须通过抽象接口或父类引用调用方法,控制权由运行时动态绑定(动态分派)决定,而非硬编码。
以上三点正是封装、继承、多态的体现,从任意跳转变为接口调用,从编译时绑定变为运行时绑定,从硬编码依赖变为松耦合协作,控制权由对象内部管理,外部代码只能通过接口请求,而非直接控制。面向对象编程通过限制谁能控制谁以及如何控制,将混乱的自由度转化为规范的交互协议,从而管理复杂性。
这里的间接转移是什么意思呢,指的是控制权的转移通过中间层(接口、回调、事件)动态决定,调用方无须知道具体的实现,比如面向对象的多态、回调函数以及依赖注入的的实现方式。
传统方式(控制权直接转移)
scss
void ProcessOrder(Order order) {
SaveToFile(order); // 直接控制
PrintReceipt(order);
UpdateInventory(order);
}
面向对象方式方式(控制权间接转移)
ini
class OrderProcessor {
private IStorage storage;
private IPrinter printer;
private IInventory inventory;
public OrderProcessor(IStorage s, IPrinter p, IInventory i) {
this.storage = s;
this.printer = p;
this.inventory = i;
}
public void Process(Order order) {
storage.Save(order); // 间接控制
printer.Print(order);
inventory.Update(order);
}
}
函数式编程
函数式编程是对程序中的赋值进行了限制和规范。这句话的意思是通过禁止随意修改变量值从而从根本上解决由可变状态引发的各类问题。
在传统命令式编程中,程序的核心逻辑往往依赖于对变量的频繁修改------通过循环累加、对象属性变更或全局状态更新等方式实现功能。这种"修改变量"的思维模式虽然直观,却隐藏着巨大风险:当多个操作在不同时间点修改同一数据时,程序会陷入"可变状态陷阱",表现为竞态条件、并发冲突、难以追踪的副作用等问题,这些问题在分布式系统和高并发场景中尤为致命。
函数式编程通过两条核心原则彻底改变了这一局面:
- 不可变数据:所有变量一旦被赋值便不可修改,任何变更都体现为新值的创建而非原地修改
- 纯函数:函数输出仅取决于输入参数,不会读取外部状态或修改外部变量
python
# 不可变数据结构(如元组)
immutable_tuple = (1, 2, 3)
new_tuple = (0,) + immutable_tuple # 创建新元组而非修改原数据
# 使用生成器而非可变列表
def squares(iterable):
return (x ** 2 for x in iterable) # 惰性计算,避免中间状态
# 纯函数示例
def pure_add(a, b):
return a + b # 无副作用,输出仅依赖输入
总结
结构化编程是对程序控制权直接转移的限制,面向对象编程是对程序控制权间接转移的限制,函数式编程是对程序中赋值操作的限制。这三个编程范式都对程序员提出了新的限制。每个范式都约束了某种编写代码的方式,没有一个编程范式是在增加新能力,也就是说,我们过去50年学到的东西主要是------什么不应该做。我们必须面对这种不友好的现实,软件构建并不是一个迅速前进的技术。今天构建软件的规则和1946年阿兰·图灵写下电子计算机的第一行代码时是一样的。尽管工具变化了,硬件变化了,但是软件编程的核心没有变。总而言之,软件,或者说计算机程序无一例外是由顺序结构、分支结构、循环结构和间接转移这几种行为组合而成的,无可增加,也缺一不可。