函数式编程通过参数传递、高阶函数、函数组合和代数数据类型替代继承:显式传入依赖如validator/processor;用高阶函数封装流程并隔离状态;以compose组合纯函数实现能力叠加;用枚举+模式匹配替代“is-a”继承,支持可扩展的“one-of”逻辑。

函数式编程风格不依赖类的层级结构,而是通过组合、纯函数和不可变数据来组织逻辑,天然规避了继承带来的状态耦合问题。关键不是“去掉继承”,而是用更松散、更可控的方式复用行为。
用参数传递替代受保护字段
继承常把共享状态(如配置、验证器、处理器)放在父类中,子类隐式依赖其生命周期和修改时机。函数式做法是显式把所需能力作为参数传入:
- 把原本放在基类里的 validator、processor 等组件,改为函数类型参数或接口值
- 调用方决定传什么实现,运行时绑定,而非编译期继承固定关系
- 例如 Go 中的
Execute(task string, v Validator, p Processor)比b.validator.Validate()更清晰地表达了依赖来源
用高阶函数封装通用流程
继承中常见的模板方法模式(如 templateMethod() { before(); doWork(); after(); }),在函数式中可被高阶函数替代:
- 定义一个函数接收 核心逻辑 和 前后钩子,返回新函数
- 钩子和主逻辑彼此隔离,不共享 this 或成员变量,无隐式状态流
- 比如:
withLogging = (f) => (...args) => { console.log('start'); const r = f(...args); console.log('end'); return r; }
用函数组合代替类组合/继承链
当多个能力需要叠加(如验证 + 日志 + 重试),面向对象容易陷入多层继承或复杂委托,而函数式直接组合:
- 每个能力是一个纯函数:validate、log、retry
- 用
compose(retry, log, validate, handler)构建新行为,顺序明确、可测、可替换 - 没有“谁继承谁”“谁拥有谁”的所有权争议,也没有因继承顺序导致的初始化冲突
用代数数据类型 + 模式匹配替代类型继承树
继承常用于表达“is-a”关系(如 Animal → Dog),但实际业务中更多是“one-of”(如请求要么是 Create,要么是 Update)。这时:
- 定义密封类型(如 Rust 的 enum、TypeScript 的 union)描述所有可能形态
- 用纯函数配合模式匹配处理每种情况,逻辑集中、无虚函数调度开销
- 新增一种类型只需扩展类型定义 + 新增分支,不改动原有类结构,避免继承体系膨胀










