一、核心原理
-
协议 = 能力契约
- 抽象行为而非具体类型
- 模块只依赖协议 → 低耦合
-
协议扩展 = 默认实现 / 模板方法
- 提供通用逻辑
- conforming 类型可覆盖 → 保持灵活性
-
类型组合 + 值类型(struct)
- struct conform 多个协议 → 高内聚
- 每个类型只关心自身能力
-
依赖注入 + 泛型约束
- 高层模块通过协议注入依赖 → 易替换 mock → 提升测试覆盖率
二、设计策略
1️⃣ 小协议、单一职责 → 高内聚
protocol Fetchable {
func fetch(id: Int) -> String
}
protocol Savable {
func save(data: String)
}
- 每个协议只关心一个功能
- 类型 conform 一个或多个协议组合能力 → 高内聚
2️⃣ 模块只依赖协议 → 低耦合
class UserService {
let fetcher: Fetchable
let saver: Savable
init(fetcher: Fetchable, saver: Savable) {
self.fetcher = fetcher
self.saver = saver
}
func updateUser(id: Int, newName: String) {
var data = fetcher.fetch(id: id)
data = newName
saver.save(data: data)
}
}
- UserService 不依赖具体类型
- Fetchable / Savable 可以在不同模块实现 → 模块间低耦合
3️⃣ 默认实现 → 可复用逻辑
extension Savable {
func save(data: String) {
print("Default save: (data)")
}
}
- 所有 conforming 类型可复用模板方法
- 高内聚逻辑集中 → 不重复实现
4️⃣ 依赖注入 + Mock → 高测试覆盖率
struct MockFetcher: Fetchable {
func fetch(id: Int) -> String { "MockUser" }
}
struct MockSaver: Savable {
func save(data: String) { print("Mock saved (data)") }
}
let service = UserService(fetcher: MockFetcher(), saver: MockSaver())
service.updateUser(id: 1, newName: "Alice")
// Mock saved Alice
- 测试不依赖真实数据库
- 每个模块都可单独测试 → 高覆盖率
- 类型替换灵活 → 易扩展
三、工程实践策略
| 策略 | 作用 |
|---|---|
| 小协议、单一职责 | 高内聚,类型只关心自身能力 |
| 模块间依赖协议 | 低耦合,替换实现不影响其他模块 |
| 协议扩展默认实现 | 提供模板方法,复用逻辑 |
| 泛型约束协议 | 核心逻辑静态派发 → 高性能 |
| 依赖注入 | 高层模块可替换依赖 → 易测试 |
| Mock / Stub | 提升单元测试覆盖率,保证模块独立测试 |
四、POP 带来的整体优势
-
高内聚
- struct / class 只 conform 所需协议
- 功能集中在能力模块 → 易理解、易维护
-
低耦合
- 模块之间通过协议交互
- 改动模块内部实现不会影响其他模块
-
高测试覆盖率
- 协议 + DI → 可注入 mock / stub
- 单元测试独立、可控
- 无需依赖真实服务或数据库
-
可复用与可扩展
- 新模块或功能直接 conform已有协议
- 默认实现 + 泛型约束 → 核心逻辑复用
五、设计口诀
“协议抽象能力 → 模块依赖协议 → 小协议高内聚 → 默认实现复用逻辑 → DI + mock 提升测试覆盖率。”