Contents
  1. 1. 从面向对象到事件化:一种编程范式的思考
    1. 1.1. 前言
    2. 1.2. 一、公开与私有:不是对立,是平衡
      1. 1.2.1. 为什么有私有方法?
      2. 1.2.2. 极端的代价
      3. 1.2.3. 结论
    3. 1.3. 二、面向对象与面向过程:不是矛盾,是互补
      1. 1.3.1. 静态方法的本质
      2. 1.3.2. 范式选择
    4. 1.4. 三、函数式编程:定义规则,而非执行步骤
      1. 1.4.1. 命令式 vs 声明式
      2. 1.4.2. 例子
      3. 1.4.3. 本质
    5. 1.5. 四、Go 对 OOP 的简化
    6. 1.6. 五、事件化模型:替代递归/栈
      1. 1.6.1. 传统模型的问题
      2. 1.6.2. 事件化模型
      3. 1.6.3. 优势
      4. 1.6.4. 已有实现
    7. 1.7. 六、生命周期管理:holder_id 模式
      1. 1.7.1. 传统方案的问题
      2. 1.7.2. 解决方案
    8. 1.8. 七、无竞争分配:预订模式
      1. 1.8.1. 传统方式
      2. 1.8.2. 事件化方式
      3. 1.8.3. 类比
    9. 1.9. 八、分布式时序:向量时钟 + 柔性事务
      1. 1.9.1. 核心思想
      2. 1.9.2. 柔性事务
    10. 1.10. 九、总结
      1. 1.10.1. 统一模式
      2. 1.10.2. 设计原则
      3. 1.10.3. 核心收益
    11. 1.11. 后记
    12. 1.12. 参考

从面向对象到事件化:一种编程范式的思考

前言

这篇文章记录了一次关于编程范式的思考,从公开/私有方法的设计,到面向对象与面向过程的关系,再到事件化模型如何解决并发问题。

核心观点:没有对立,只有平衡;没有非此即彼,只有恰到好处。


一、公开与私有:不是对立,是平衡

为什么有私有方法?

封装(Encapsulation)的目的:

  • 隐藏实现细节
  • 减少耦合
  • 简化使用
极端的代价
极端 问题
全公开 改不动,到处是依赖
全私有 没法用,没法测
结论

如果一个私有方法复杂到需要单独测试,它就不应该是私有的。

私有方法的本意是”简单的实现细节”。复杂逻辑应该提取成独立的可测试单元。


二、面向对象与面向过程:不是矛盾,是互补

静态方法的本质
// Java 的静态方法
Math.abs(-1)

// Go 的包级函数
math.Abs(-1)

静态方法 = 披着 OOP 外衣的面向过程

Java/C# 要求所有代码必须在类里,但有些逻辑不需要对象状态(如 Math.abs()),所以用 static 妥协。

范式选择
场景 适合范式
管理状态 + 行为 面向对象
纯计算、无状态 面向过程 / 函数式
数据变换 函数式

好代码 = 混合使用,按需选择。


三、函数式编程:定义规则,而非执行步骤

命令式 vs 声明式
命令式(过程式/OOP):怎么做
  1. 拿个变量
  2. 循环
  3. 累加
  4. 返回

函数式:是什么
  factorial = n → n * factorial(n-1)
  就是数学定义,映射关系
例子
风格 求和
命令式 sum=0; for(i:list) sum+=i; return sum;
函数式 sum = reduce(+, list)
本质

函数式 ≈ 定义规则 / 数学映射
面向过程 ≈ 描述步骤 / 执行流程


四、Go 对 OOP 的简化

传统 OOP 的问题:

  • 继承层次太深
  • 设计模式满天飞
  • 过度抽象

Go 的做法:

传统 OOP Go
class Dog extends Animal type Dog struct { Animal }
class Dog implements Pet 有方法就算实现(鸭子类型)
继承链 扁平组合

组合优于继承。


五、事件化模型:替代递归/栈

传统模型的问题
调用 → 入栈 → 返回 → 出栈
        ↓
    共享状态
        ↓
    锁、竞态、死锁
事件化模型
函数 A:
  处理 → 发出事件 E1
              ↓
函数 B 收到 E1:
  处理 → 发出事件 E2
              ↓
函数 C 收到 E2:
  处理 → 不再发出事件
              ↓
         生命周期结束
优势
  • 无共享状态
  • 天然异步,不需要 async/await
  • 无锁、无竞态
已有实现
技术 体现
Erlang/Elixir Actor + 消息传递
Go goroutine + channel
JavaScript 事件循环

六、生命周期管理:holder_id 模式

传统方案的问题
  • 消息复制有性能开销
  • 引用传递有生命周期追踪问题
解决方案
事件 {
    data,
    holder_id    // 当前持有者(队列或处理者)
}

holder_id == null → 可回收

像接力棒

  • 棒上写着当前持有人
  • 传出去就不再是你的
  • 没人拿就可以扔掉

七、无竞争分配:预订模式

传统方式
事件产生 → 多人抢 → 锁
事件化方式
生产者生成事件时:
  事件 {
      data,
      target_id: 处理者3,   // 生成时就定了
  }
        ↓
直接发到处理者3的信箱
        ↓
根本不存在竞争
类比
传统:到酒店门口排队抢房
事件化:提前预订,到了直接入住

声明关系,而不是执行抢夺。


八、分布式时序:向量时钟 + 柔性事务

核心思想
不追求"绝对时间一致"
        ↓
只追求"相对顺序可推算"
        ↓
每个节点记录:我比谁快/慢多少
        ↓
读写时本地计算全局顺序
柔性事务
  • 不追求强一致性
  • 允许中间状态不一致
  • 最终结果一致
  • 对时间隔按业务动态调整
业务场景 对时间隔 一致性
金融交易 短(毫秒级)
社交点赞 长(秒/分钟级)
日志采集 很长 最终

九、总结

统一模式
看似对立的概念
      ↓
其实是需要平衡的两端
      ↓
好设计 = 按需在中间取点
      ↓
极端 = 问题
设计原则
原则 说明
无共享 状态隔离,消息传递
关系前置 生成时绑定,而非运行时竞争
声明式 定义规则,而非执行步骤
动态权衡 一致性/性能按业务调整
核心收益
问题 解决方式
并发竞态 无共享状态,只有消息
生命周期 holder_id 轻量追踪
死锁 无锁,只有消息队列
async/await 不需要,天然异步
分布式事务 柔性事务 + 动态对时

后记

编程范式不是信仰,是工具。

面向过程解决「怎么算」
面向对象解决「怎么组织」
函数式解决「怎么声明」
事件化解决「怎么并发」

没有银弹,只有 trade-off。场景决定方案,不是方案决定场景。


参考

  • Erlang/OTP: Actor 模型
  • Go: goroutine + channel
  • Rust: Ownership + Borrowing
  • Lamport Clock / Vector Clock
  • CAP 定理与 BASE 理论
Contents
  1. 1. 从面向对象到事件化:一种编程范式的思考
    1. 1.1. 前言
    2. 1.2. 一、公开与私有:不是对立,是平衡
      1. 1.2.1. 为什么有私有方法?
      2. 1.2.2. 极端的代价
      3. 1.2.3. 结论
    3. 1.3. 二、面向对象与面向过程:不是矛盾,是互补
      1. 1.3.1. 静态方法的本质
      2. 1.3.2. 范式选择
    4. 1.4. 三、函数式编程:定义规则,而非执行步骤
      1. 1.4.1. 命令式 vs 声明式
      2. 1.4.2. 例子
      3. 1.4.3. 本质
    5. 1.5. 四、Go 对 OOP 的简化
    6. 1.6. 五、事件化模型:替代递归/栈
      1. 1.6.1. 传统模型的问题
      2. 1.6.2. 事件化模型
      3. 1.6.3. 优势
      4. 1.6.4. 已有实现
    7. 1.7. 六、生命周期管理:holder_id 模式
      1. 1.7.1. 传统方案的问题
      2. 1.7.2. 解决方案
    8. 1.8. 七、无竞争分配:预订模式
      1. 1.8.1. 传统方式
      2. 1.8.2. 事件化方式
      3. 1.8.3. 类比
    9. 1.9. 八、分布式时序:向量时钟 + 柔性事务
      1. 1.9.1. 核心思想
      2. 1.9.2. 柔性事务
    10. 1.10. 九、总结
      1. 1.10.1. 统一模式
      2. 1.10.2. 设计原则
      3. 1.10.3. 核心收益
    11. 1.11. 后记
    12. 1.12. 参考