【问题标题】:How can I design a generic observer pattern protocol in Swift?如何在 Swift 中设计一个通用的观察者模式协议?
【发布时间】:2019-03-28 02:08:39
【问题描述】:

我想为观察者模式设计一个通用的 Swift 协议,以用于不同的类型/类。问题是我似乎无法为观察者的notify() 方法指定类型。

最初,我尝试使用我的Observer 协议创建一个associatedtype

protocol Observer {
    associatedtype T
    func notify(_ value: T)
}

protocol Observable {
    var observers: [Observer] { get set }
    func registerObserver(_ observer: Observer)
    func unregisterObserver(_ observer: Observer)
}

这不起作用(编译错误):error: protocol 'Observer' can only be used as a generic constraint because it has Self or associated type requirements

所以我尝试改用泛型方法:

protocol Observer {
    func notify<T>(_ value: T)
}

protocol Observable {
    associatedtype T
    var observers: [Observer] { get set } // This is okay now
}

extension Observable {
    // implement registerObserver()
    // implement unregisterObserver()

    func notifyObservers<T>(_ value: T) {
        for observer in observers {
            observer.notify(value)
        }
    }
}

这很好用,但会产生一些非常有趣的结果。为了测试它,我创建了FooObserverFooObservable

class FooObserver: Observer {
    func notify<T>(_ value: T) {
        print(value)
    }
}

class FooObservable: Observable {
    typealias T = Int // For simplicity I set T to Int type
    var observers: [Observer] = []
}

let a = FooObserver()
let b = FooObserver()
var c = FooObservable()
c.registerObserver(a)
c.registerObserver(b)
c.notifyObservers("hello") // This works, but why?

我能够成功地通知我的 2 个观察者字符串“hello”。我猜这与类型擦除有关...?

所以我的问题是:如何实现泛型类型的观察者模式,我可以确定notify() 中的值是正确的类型?

【问题讨论】:

    标签: swift generics protocols observer-pattern


    【解决方案1】:
    protocol Observer {
        associatedtype T
        func notify(_ value: T)
    }
    

    这表示给定的观察者可以处理观察者选择的一种特定类型 (T)。

    protocol Observable {
        var observers: [Observer] { get set }
        func registerObserver(_ observer: Observer)
        func unregisterObserver(_ observer: Observer)
    }
    

    这是无效的,因为系统无法知道T 这些观察者想要什么。每个观察者只能处理一个T

    protocol Observer {
        func notify<T>(_ value: T)
    }
    

    这基本上没有意义。它说 notify 可以用任何类型调用。如果这就是你的意思,你想说:

    protocol Observer {
        func notify(_ value: Any)
    }
    

    但这意味着每个观察者都必须处理Any,这并不好。它碰巧起作用的原因是您选择了print 作为您的测试。 print 可以处理Any。当你想测试这些东西时,你需要尝试一些你真正想要在你的程序中做的事情。打印适用于对任何其他目的无用的各种事物。

    基本问题是Observer 不应该是协议。它应该是一个函数。例如:

    typealias Observer<T> = (T) -> Void
    
    protocol Observable {
        associatedtype T
        var observers: [Observer<T>] { get set }
        func registerObserver(_ observer: Observer<T>)
        func unregisterObserver(_ observer: Observer<T>)
    }
    

    这种方法的问题是无法实现unregisterObserver。我也不清楚您是如何在代码中实现 unregisterObserver 的。看起来不太可能。

    这是构建 observable 的一种非常简单的方法:

    typealias Observer<T> = (T) -> ()
    
    struct Subscription {
        let cancel: () -> Void
    }
    
    final class Observable<T> {
        private var observations: [UUID: Observer<T>] = [:]
        func subscribe(observer: @escaping Observer<T>) -> Subscription {
            let uuid = UUID()
            observations[uuid] = observer
            return Subscription(cancel: { [weak self] in self?.observations[uuid] = nil })
        }
    }
    

    (请参阅 https://stackoverflow.com/a/55389143/97337 了解其来源。)

    如需更完整且非常简单的版本,请参阅Observable。对于有点古怪的更复杂的版本,请参阅Stream。如需更强大且不那么古怪的版本,请参阅Properties。有关建立完整编程方式的非常强大的版本,请参阅RxSwift

    【讨论】:

    • 谢谢!这很有帮助 :) 您对 Observable 的实现可能对我的需求来说有点过于复杂,但它确实很有启发性!
    猜你喜欢
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 2011-09-25
    相关资源
    最近更新 更多