繁体   English   中英

如何在Swift中设计通用观察者模式协议?

[英]How can I design a generic observer pattern protocol in Swift?

我想为观察者模式设计一个通用的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?

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

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

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 看起来真的不太可能。

这是一种构建可观察对象的非常简单的方法:

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 有关功能更强大且不太古怪的版本,请参见属性 有关建立完整编程方式的非常强大的版本,请参见RxSwift

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM