4-20.【协议导向编程】举例说明如何将一个典型 OOP 架构(如 MVC)改造为 POP 架构。

0 阅读2分钟

一、典型 OOP MVC(面向对象)

// Model
class User {
    var name: String
    init(name: String) { self.name = name }
}

// View
class UserView: UIView {
    func display(name: String) {
        print("User name: (name)")
    }
}

// Controller
class UserController {
    var user: User
    var view: UserView
    
    init(user: User, view: UserView) {
        self.user = user
        self.view = view
    }
    
    func updateUserName(_ name: String) {
        user.name = name
        view.display(name: user.name)
    }
}

// 使用
let user = User(name: "Alice")
let view = UserView()
let controller = UserController(user: user, view: view)
controller.updateUserName("Bob")

特点:

  • User / UserView / UserController 都是 class
  • Controller tightly coupled User 和 UserView
  • 动态派发 → 修改行为可能影响整个继承链
  • 值类型不易复用

二、OOP MVC 的问题

  1. 耦合度高

    • Controller 知道具体 User / UserView 类型
  2. 难以复用或替换

    • 想换不同类型 View / Model → 只能继承或泛型
  3. 深层动态派发

    • OOP class 多态层级复杂 → 维护难

三、POP 改造思路

原则:

  1. 抽象行为 → 协议(Protocol)

    • Model 读写、View 显示、Controller 调度
  2. 默认实现 → extension

    • 提供模板方法、工具函数
  3. 组合能力 → struct / class conform 多协议

    • 解耦,支持值类型
  4. 泛型 +协议约束 → 多态

    • Controller 不依赖具体类型,只依赖能力

四、POP 改造示例

// 1️⃣ Model 行为协议
protocol UserModel {
    var name: String { get set }
}

// 2️⃣ View 行为协议
protocol UserViewable {
    func display(name: String)
}

// 3️⃣ Controller 行为协议
protocol UserControllable {
    associatedtype Model: UserModel
    associatedtype View: UserViewable
    
    var user: Model { get set }
    var view: View { get }
    
    func updateUserName(_ name: String)
}

// 4️⃣ Controller 默认实现(模板方法)
extension UserControllable {
    func updateUserName(_ name: String) {
        var mutableUser = user
        mutableUser.name = name
        view.display(name: mutableUser.name)
    }
}

// 5️⃣ 具体类型
struct User: UserModel {
    var name: String
}

struct UserView: UserViewable {
    func display(name: String) {
        print("User name: (name)")
    }
}

struct UserController: UserControllable {
    var user: User
    let view: UserView
}

// 6️⃣ 使用
var user = User(name: "Alice")
let view = UserView()
let controller = UserController(user: user, view: view)
controller.updateUserName("Bob") // 输出: User name: Bob

五、POP 改造特点

  1. 解耦

    • Controller 不依赖具体 User / UserView 类型,只依赖协议
    • 以后换不同 Model / View 都可行
  2. 支持值类型

    • Model / Controller 都可以用 struct
    • 默认实现 + 泛型保证多态
  3. 复用模板方法

    • Controller 的 updateUserName 默认实现可以被复用或覆盖
  4. 易测试 / 可扩展

    • 可以用 MockUser / MockView 测试
    • 添加新行为只需新增协议,不破坏原有结构

六、工程级建议

  1. 每个组件行为 → 协议
  2. 模板方法放在 extension
  3. Controller 使用泛型约束协议
  4. 具体类型 struct + conform 协议 → 高性能 + 易组合
  5. 多协议组合 → 替代深继承层级

总结

OOP MVC 强调类型继承 → Controller tightly coupled
POP MVC 强调行为契约 → Controller 依赖协议 + 默认实现 + 泛型 → 解耦、可组合、可测试