1️⃣ 核心思路
目标:把数据处理逻辑设计成可组合的流水线,同时:
- 核心处理逻辑保持纯函数
- 副作用(打印、网络、文件写入)集中在最外层
原则:
- 纯函数 → 只处理数据,不依赖外部状态
- 副作用函数 → 接收纯函数输出,执行打印/存储/网络等
流水线 = 多个纯函数组合 → 最终执行副作用
2️⃣ 示例场景
假设我们有一个字符串数组,需要做以下处理:
- 去除长度 ≤ 3 的字符串
- 转成大写
- 统计每个字符串长度
- 输出日志(副作用)
3️⃣ 使用纯函数 + 副作用分离实现
步骤 1:定义纯函数
// 过滤短字符串
func filterShortStrings(_ strings: [String]) -> [String] {
return strings.filter { $0.count > 3 }
}
// 转大写
func toUpperCase(_ strings: [String]) -> [String] {
return strings.map { $0.uppercased() }
}
// 计算长度
func stringLengths(_ strings: [String]) -> [Int] {
return strings.map { $0.count }
}
- 输入 → 输出完全由参数决定
- 无打印、无修改外部状态
✅ 都是纯函数
步骤 2:组合流水线
func processData(_ strings: [String]) -> [Int] {
let filtered = filterShortStrings(strings)
let uppercased = toUpperCase(filtered)
return stringLengths(uppercased)
}
- 可以链式调用或组合纯函数
- 流水线核心逻辑完全纯净
步骤 3:集中副作用
func printResult(_ results: [Int]) {
print("Processed string lengths:", results)
}
- 只在最后一步打印,副作用集中
- 核心处理逻辑不依赖打印
步骤 4:使用
let words = ["apple", "is", "good", "for", "health"]
let lengths = processData(words) // 纯函数流水线
printResult(lengths) // 副作用执行
// 输出:Processed string lengths: [5, 4, 6]
4️⃣ 可进一步函数式优化
可以使用链式函数式写法(更简洁):
let lengths = ["apple", "is", "good", "for", "health"]
.filter { $0.count > 3 }
.map { $0.uppercased() }
.map { $0.count } // 纯函数链
print("Processed string lengths:", lengths) // 副作用在这里
- 流水线逻辑完全纯函数化
- 副作用只在最后的
print
5️⃣ 优势
| 优势 | 说明 |
|---|---|
| 可测试 | 核心函数无副作用,可单元测试 |
| 可组合 | 每个函数独立,可重用或组合 |
| 并发安全 | 纯函数天然线程安全 |
| 易维护 | 副作用集中管理,逻辑清晰 |
✅ 总结设计模式
- 纯函数层 → 数据转换、过滤、映射、计算
- 副作用层 → 日志打印、文件写入、网络请求
- 流水线执行 → 纯函数处理数据 → 副作用层执行最终输出