26-面向协议编程

141 阅读6分钟

Swift 面向协议编程(POP)详解

目录


面向协议编程概述

面向协议编程(Protocol Oriented Programming,简称POP)是Swift的一种编程范式,Apple于2015年WWDC提出。在Swift的标准库中,能见到大量POP的影子。

什么是面向协议编程?

POP是一种设计理念,强调:

  • 行为优先:先定义行为,再实现具体类型
  • 组合优于继承:通过协议组合实现复杂功能
  • 代码复用:通过协议扩展提供默认实现

OOP vs POP

面向对象编程(OOP)回顾

// OOP - 继承层次结构
class Animal {
    func makeSound() {
        print("Some sound")
    }
}

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

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

面向协议编程(POP)

// POP - 协议定义行为
protocol Animal {
    func makeSound()
}

struct Dog: Animal {
    func makeSound() {
        print("Woof!")
    }
}

struct Cat: Animal {
    func makeSound() {
        print("Meow!")
    }
}

对比分析

特性OOPPOP
代码复用继承协议扩展
类型系统引用类型值类型 + 引用类型
多态子类多态协议多态
耦合度较高较低
灵活性受限于继承层次更加灵活

协议的优势

1. 避免继承的限制

// OOP的问题:单继承限制
class Vehicle {
    func move() { print("Moving") }
}

class FlyingVehicle: Vehicle {
    func fly() { print("Flying") }
}

// 如果需要既能游泳又能飞行的交通工具,继承就有问题了

// POP的解决方案:协议组合
protocol Movable {
    func move()
}

protocol Flyable {
    func fly()
}

protocol Swimmable {
    func swim()
}

struct Amphibian: Movable, Flyable, Swimmable {
    func move() { print("Moving") }
    func fly() { print("Flying") }
    func swim() { print("Swimming") }
}

2. 更好的代码复用

// 通过协议扩展提供默认实现
protocol Drawable {
    func draw()
}

extension Drawable {
    func draw() {
        print("Drawing...")
    }
    
    func prepareForDrawing() {
        print("Preparing for drawing")
    }
}

struct Circle: Drawable {
    // 可以使用默认实现,也可以重写
}

struct Rectangle: Drawable {
    func draw() {
        print("Drawing rectangle")
    }
}

协议基础

协议定义

protocol Identifiable {
    var id: String { get }
    func uniqueIdentifier() -> String
}

protocol Nameable {
    var name: String { get set }
}

protocol Describable {
    var description: String { get }
}

协议实现

struct User: Identifiable, Nameable, Describable {
    let id: String
    var name: String
    
    var description: String {
        return "User: \(name) (\(id))"
    }
    
    func uniqueIdentifier() -> String {
        return "USER_\(id)"
    }
}

协议扩展

提供默认实现

protocol Loggable {
    func log(_ message: String)
}

extension Loggable {
    func log(_ message: String) {
        print("[LOG] \(message)")
    }
    
    func debug(_ message: String) {
        print("[DEBUG] \(message)")
    }
    
    func error(_ message: String) {
        print("[ERROR] \(message)")
    }
}

struct NetworkManager: Loggable {
    func fetchData() {
        log("Fetching data...")
        // 网络请求逻辑
        debug("Data fetched successfully")
    }
}

有条件的协议扩展

protocol Collection {
    associatedtype Element
    var count: Int { get }
    subscript(index: Int) -> Element { get }
}

extension Collection where Element: Comparable {
    func sorted() -> [Element] {
        // 排序实现
        return []
    }
}

extension Collection where Element: Numeric {
    func sum() -> Element {
        // 求和实现
        return Element.zero
    }
}

协议组合

基本协议组合

protocol Readable {
    func read() -> String
}

protocol Writable {
    func write(_ content: String)
}

// 协议组合
typealias ReadWritable = Readable & Writable

class File: ReadWritable {
    func read() -> String {
        return "File content"
    }
    
    func write(_ content: String) {
        print("Writing: \(content)")
    }
}

// 使用组合协议
func processFile(_ file: ReadWritable) {
    let content = file.read()
    file.write("Processed: \(content)")
}

复杂协议组合

protocol Cacheable {
    func cache()
}

protocol Validatable {
    func validate() -> Bool
}

protocol Serializable {
    func serialize() -> Data
}

// 复合协议
typealias CacheableValidatableSerializable = Cacheable & Validatable & Serializable

struct UserData: CacheableValidatableSerializable {
    func cache() {
        print("Caching user data")
    }
    
    func validate() -> Bool {
        return true
    }
    
    func serialize() -> Data {
        return Data()
    }
}

泛型协议

关联类型

protocol Container {
    associatedtype Item
    
    var count: Int { get }
    mutating func append(_ item: Item)
    subscript(index: Int) -> Item { get }
}

struct IntContainer: Container {
    typealias Item = Int
    
    private var items: [Int] = []
    
    var count: Int {
        return items.count
    }
    
    mutating func append(_ item: Int) {
        items.append(item)
    }
    
    subscript(index: Int) -> Int {
        return items[index]
    }
}

泛型约束

protocol Comparable {
    static func < (lhs: Self, rhs: Self) -> Bool
}

protocol SortableContainer: Container where Item: Comparable {
    func sorted() -> [Item]
}

extension SortableContainer {
    func sorted() -> [Item] {
        var result: [Item] = []
        for i in 0..<count {
            result.append(self[i])
        }
        return result.sorted(by: <)
    }
}

实际应用

1. MVVM架构中的协议

// View协议
protocol ViewProtocol: AnyObject {
    func showLoading()
    func hideLoading()
    func showError(_ message: String)
}

// ViewModel协议
protocol ViewModelProtocol {
    func loadData()
    func refresh()
}

// 具体实现
class UserListViewController: UIViewController, ViewProtocol {
    var viewModel: ViewModelProtocol?
    
    func showLoading() {
        // 显示加载指示器
    }
    
    func hideLoading() {
        // 隐藏加载指示器
    }
    
    func showError(_ message: String) {
        // 显示错误信息
    }
}

class UserListViewModel: ViewModelProtocol {
    weak var view: ViewProtocol?
    
    func loadData() {
        view?.showLoading()
        // 加载数据
        view?.hideLoading()
    }
    
    func refresh() {
        loadData()
    }
}

2. 网络层设计

protocol NetworkServiceProtocol {
    func request<T: Codable>(_ endpoint: Endpoint) -> Future<T, Error>
}

protocol CacheServiceProtocol {
    func get<T: Codable>(_ key: String, type: T.Type) -> T?
    func set<T: Codable>(_ value: T, forKey key: String)
}

protocol LoggingServiceProtocol {
    func log(_ message: String)
}

// 组合服务
class APIManager: NetworkServiceProtocol, CacheServiceProtocol, LoggingServiceProtocol {
    func request<T: Codable>(_ endpoint: Endpoint) -> Future<T, Error> {
        log("Making request to \(endpoint)")
        // 网络请求实现
    }
    
    func get<T: Codable>(_ key: String, type: T.Type) -> T? {
        // 缓存获取实现
        return nil
    }
    
    func set<T: Codable>(_ value: T, forKey key: String) {
        // 缓存设置实现
    }
    
    func log(_ message: String) {
        print("[API] \(message)")
    }
}

3. 数据存储抽象

protocol DataStore {
    associatedtype Key
    associatedtype Value
    
    func get(_ key: Key) -> Value?
    func set(_ value: Value, forKey key: Key)
    func remove(_ key: Key)
}

// 内存存储
class MemoryDataStore<Key: Hashable, Value>: DataStore {
    private var storage: [Key: Value] = [:]
    
    func get(_ key: Key) -> Value? {
        return storage[key]
    }
    
    func set(_ value: Value, forKey key: Key) {
        storage[key] = value
    }
    
    func remove(_ key: Key) {
        storage.removeValue(forKey: key)
    }
}

// 磁盘存储
class DiskDataStore: DataStore {
    typealias Key = String
    typealias Value = Data
    
    func get(_ key: String) -> Data? {
        // 从磁盘读取
        return nil
    }
    
    func set(_ value: Data, forKey key: String) {
        // 写入磁盘
    }
    
    func remove(_ key: String) {
        // 删除文件
    }
}

设计模式

1. 策略模式

protocol SortingStrategy {
    func sort<T: Comparable>(_ array: [T]) -> [T]
}

struct BubbleSort: SortingStrategy {
    func sort<T: Comparable>(_ array: [T]) -> [T] {
        // 冒泡排序实现
        return array.sorted()
    }
}

struct QuickSort: SortingStrategy {
    func sort<T: Comparable>(_ array: [T]) -> [T] {
        // 快速排序实现
        return array.sorted()
    }
}

class Sorter {
    private var strategy: SortingStrategy
    
    init(strategy: SortingStrategy) {
        self.strategy = strategy
    }
    
    func sort<T: Comparable>(_ array: [T]) -> [T] {
        return strategy.sort(array)
    }
}

2. 观察者模式

protocol Observer: AnyObject {
    func update(_ data: Any)
}

protocol Observable {
    func addObserver(_ observer: Observer)
    func removeObserver(_ observer: Observer)
    func notifyObservers(_ data: Any)
}

class Subject: Observable {
    private var observers: [Observer] = []
    
    func addObserver(_ observer: Observer) {
        observers.append(observer)
    }
    
    func removeObserver(_ observer: Observer) {
        observers.removeAll { $0 === observer }
    }
    
    func notifyObservers(_ data: Any) {
        observers.forEach { $0.update(data) }
    }
}

最佳实践

1. 小而专一的协议

// 好的做法:小而专一
protocol Readable {
    func read() -> String
}

protocol Writable {
    func write(_ content: String)
}

// 避免:大而全的协议
protocol FileOperations {
    func read() -> String
    func write(_ content: String)
    func delete()
    func move(to path: String)
    func copy(to path: String)
    func compress()
    func decompress()
}

2. 使用协议扩展提供默认实现

protocol Equatable {
    static func == (lhs: Self, rhs: Self) -> Bool
}

extension Equatable {
    static func != (lhs: Self, rhs: Self) -> Bool {
        return !(lhs == rhs)
    }
}

3. 优先使用值类型

// 优先使用struct实现协议
struct Point: Equatable {
    let x: Double
    let y: Double
    
    static func == (lhs: Point, rhs: Point) -> Bool {
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
}

// 而不是class
class PointClass: Equatable {
    let x: Double
    let y: Double
    
    init(x: Double, y: Double) {
        self.x = x
        self.y = y
    }
    
    static func == (lhs: PointClass, rhs: PointClass) -> Bool {
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
}

4. 合理使用关联类型

protocol Sequence {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
    
    func makeIterator() -> Iterator
}

extension Sequence {
    func map<T>(_ transform: (Element) -> T) -> [T] {
        var result: [T] = []
        for element in self {
            result.append(transform(element))
        }
        return result
    }
}

总结

面向协议编程是Swift的重要特性,它弥补了面向对象编程的一些不足,提供了更灵活、更安全的代码组织方式。

关键点回顾

  • POP强调行为优先,组合优于继承
  • 协议扩展提供默认实现,提高代码复用
  • 协议组合支持多重继承的效果
  • 泛型协议增强了类型安全性

POP的优势

  • 更好的代码复用
  • 更低的耦合度
  • 更强的类型安全
  • 更灵活的设计

使用建议

  1. 从协议开始设计:先定义行为,再实现类型
  2. 小而专一:每个协议只负责一个职责
  3. 善用扩展:通过协议扩展提供默认实现
  4. 优先值类型:使用struct而不是class实现协议

注意:POP和OOP不是对立的关系,而是相辅相成的。在实际开发中,应该根据具体场景选择合适的编程范式。