很多开发者(包括经验丰富的)都会遇到类似情况:明明知道某个技术概念(比如 Protocol),但在实际编码时却想不起来用。这其实是一个非常普遍的学习阶段现象。
一、为什么知道 Protocol 却想不起用?
1. 知识与应用存在断层
- 知道 ≠ 会用:学习技术概念时,我们往往停留在"知道它是什么",但缺乏"什么时候用它"的直觉。
- 示例:就像知道螺丝刀的存在,但看到松动的螺丝时,第一反应可能是用手去拧,而不是找螺丝刀。
2. 惯性思维主导
- 习惯性用
if-else:面对具体问题时,大脑会优先调用最熟悉的解决方案(比如条件分支),而不是评估所有可能性。 - 思维路径:“我需要判断不同类 → 用
isKindOfClass:→ 写一堆if-else"而不是:“这些类有共同行为 → 应该抽象成协议”。
3. 缺乏设计模式的敏感度
- Protocol 的本质是抽象行为约定,但初学者往往更关注具体实现细节(比如如何写方法),而忽略抽象设计。
4. 对 Protocol 的理解不够深刻
- 可能你目前对 Protocol 的认知停留在:
- “它是声明方法的列表”(表面)
- 而不是:“它是解耦和扩展架构的工具”(本质)。
二、如何培养「用 Protocol」的思维?
1. 建立「行为抽象」的条件反射
- 遇到以下场景时,强制自己思考 Protocol:
- 多个类有相同的方法名(比如你的
incrementShareCount)。 - 需要判断对象是否能响应某个方法(
respondsToSelector:)。 - 代码中出现
if ([obj isKindOfClass:[XXX class]])。 - 需要跨模块通信(如 Delegate 模式)。
- 多个类有相同的方法名(比如你的
- 口诀:“重复方法?抽象它!类型判断?协议化!跨类调用?定义协议!”
2. 从模仿优秀代码开始
研究 Apple 官方代码:iOS SDK 中大量使用 Protocol(如
UITableViewDataSource,NSCopying)。思考为什么这些场景要用 Protocol。示例:
// 为什么 UITableView 不直接提供数据,而是通过 DataSource 协议? // 答案:解耦!UITableView 不需要知道数据来源是数组、CoreData 还是网络。
3. 重构练习:将现有代码改为 Protocol 实现
具体步骤:
- 找到一段用
if-else或isKindOfClass:的代码。 - 思考:这些分支是否在处理同一类行为?
- 如果是,提取一个 Protocol,让相关类遵守它。
- 用
conformsToProtocol:替换类型判断。
- 找到一段用
你的案例重构:
// Before: 用 isKindOfClass: 判断 if ([self isKindOfClass:[NewsDetailViewController class]]) { ... } // After: 用 Protocol 判断 if ([self conformsToProtocol:@protocol(ShareCountIncrementable)]) { ... }
4. 学习设计原则
- SOLID 原则(尤其是以下两条):
- 开闭原则(OCP):代码应对扩展开放,对修改关闭。你的
shareNewsMenuHelper:方法不应该因为新增支持类而被修改。 - 依赖倒置原则(DIP):依赖抽象(Protocol),而不是具体实现(
NewsDetailViewController)。
- 开闭原则(OCP):代码应对扩展开放,对修改关闭。你的
- Protocol 如何满足 SOLID:通过定义
ShareCountIncrementable,未来新增支持类时只需遵守协议,无需修改shareNewsMenuHelper:。
5. 可视化思考工具
画类图:用纸笔或工具(如 PlantUML)画出类之间的关系。如果多个类指向同一行为,就该用 Protocol。
[NewsDetailViewController] ..|> [ShareCountIncrementable] [DouYinViewController] ..|> [ShareCountIncrementable] [ShortDramaViewController] ..|> [ShareCountIncrementable]
6. 代码审查时主动提问
- 每次提交代码前问自己:
- “这里是否有重复行为可以抽象?”
- “是否可以用 Protocol 替代类型判断?”
- “如果未来新增类似功能,是否需要修改现有代码?”
三、Protocol 思维的进阶技巧
1. 区分「是什么」和「能做什么」
- Bad: 判断对象"是什么”(
isKindOfClass:)。“你是NewsDetailViewController吗?” - Good: 判断对象"能做什么"(
conformsToProtocol:)。“你能增加分享计数吗?”
2. 结合多态使用
Protocol 的真正威力在于多态。例如:
NSArray<id<ShareCountIncrementable>> *allShareCounters = @[vc1, vc2, vc3]; for (id<ShareCountIncrementable> counter in allShareCounters) { [counter incrementShareCount]; // 无需关心具体类 }
3. 替代继承的利器
- 如果多个类的共同行为无法通过继承抽象(比如它们已经是不同子类),就用 Protocol。
4. Protocol + Default Implementation
通过 Category 为 Protocol 提供默认实现(类似 Swift 的 Protocol Extension):
// ShareCountIncrementable+Default.m @implementation NSObject (ShareCountIncrementableDefault) - (void)incrementShareCount { NSLog(@"Default: Share count incremented for %@", self); } @end这样即使某些类未实现方法,也不会崩溃。
四、实战训练题目
- 场景:你发现代码中有多处
if ([obj respondsToSelector:@selector(showError)])。任务:用 Protocol 重构。 - 场景:
NetworkManager需要将数据分别传递给HomeVC、ProfileVC,但它们接收数据的方法名不同(updateHomeData:vsreloadProfile:)。任务:设计一个DataReceivable协议统一接口。
总结
培养 Protocol 思维的关键是:
- 建立行为抽象的敏感度(看到重复方法或类型判断就想到 Protocol)。
- 从具体案例中提炼模式(多分析 Apple 的代码和自己的代码)。
- 通过重构巩固习惯(定期回顾旧代码,思考如何用 Protocol 改进)。
坚持几周后,你会发现 Protocol 就像呼吸一样自然! 🚀