4-19.【协议导向编程】在什么场景下仍然推荐面向对象而不是面向协议?

0 阅读2分钟

一、核心原则

当你的设计依赖“引用语义 + 动态派发 + 继承层次”时,用 OOP 更自然。
当你设计依赖“行为契约 + 值类型 +组合能力”时,用 POP 更好。


二、典型推荐 OOP 的场景

场景原因示例
1️⃣ UIKit / AppKit 或其他框架依赖类层级框架 API 已经用 class、多态依赖 vtableUIView 子类化
2️⃣ 状态共享 / 引用语义很重要class 是引用类型,值类型无法共享状态一个共享缓存、或单例对象
3️⃣ 复杂动态派发动态选择具体实现时频繁切换类型游戏对象系统:不同 Enemy 类型动态选择方法
4️⃣ 多态行为依赖继承链子类依赖父类部分实现NSOperation 子类重写 main() 方法
5️⃣ 生命周期管理依赖 ARC 引用struct 无法被弱引用复杂对象图中,循环引用管理需要 class

三、示例对比

1️⃣ 引用语义场景

class Counter {
    var value = 0
    func increment() { value += 1 }
}

let c1 = Counter()
let c2 = c1
c2.increment()
print(c1.value) // 输出 1 ✅ 共享引用
  • struct / POP 无法共享同一状态(值类型复制)
  • 这里用 class 更自然

2️⃣ UIKit 子类化

class CustomButton: UIButton {
    override func layoutSubviews() {
        super.layoutSubviews()
        // 调整布局
    }
}
  • 必须继承 UIButton
  • protocol + struct 无法替代

3️⃣ 复杂多态逻辑依赖继承

class Animal {
    func speak() { print("Animal") }
}

class Dog: Animal {
    override func speak() { print("Woof") }
}

class Cat: Animal {
    override func speak() { print("Meow") }
}

let a: Animal = Dog()
a.speak()  // Woof
  • 动态类型切换 → class 多态天然
  • 用 POP struct + protocol 会复杂,需要类型擦除或泛型包装

四、工程级总结规则

  1. 依赖引用语义 → OOP
  2. 依赖现有 class 框架 → OOP
  3. 多态深层继承链、动态行为复杂 → OOP
  4. 可复用、解耦、值类型组合 → POP
  5. 共享状态小、性能敏感 → POP + struct +泛型

🔑 口诀

POP 做能力组合、值类型、解耦复用;
OOP 做状态共享、引用语义、深层多态。