我想使用 SE-0142(相关类型约束) 制作一个带有2个协议的观察者模式。IsObserver
和 HasObservers
(像服务器一样),那里有一个共享的 DataType
表示被观察事物的类型。
我需要符合以下条件的对象 HasObservers
能够成为一个结构或一个类,而我想让 IsObserver
要故意限制为一个类(想要,但不需要)。
我不善于做属类......经过几个小时的努力,我做到了这一步,下面一行注释中的编译器错误。我被卡住了,不知道下一步该怎么走,我不知道这种方法是否可行,是否合理。非常感谢大家的帮助!
import Foundation
protocol IsObserver: class {
associatedtype DataType
func dataDidUpdate(_ data: [DataType])
}
struct Observation<T: IsObserver> {
weak var observer: T?
}
protocol HasObservers {
associatedtype DataType : IsObserver where DataType.DataType == DataType
static var observations: [ObjectIdentifier : Observation<IsObserver>] { get set } // ERROR: "Value of protocol type 'IsObserver' cannot conform to 'IsObserver'; only struct/enum/class types can conform to protocols"
static func tellObserversDataDidUpdate(_ data: [DataType])
}
extension HasObservers {
static func tellObserversDataDidUpdate(_ data: [DataType]) {
for (id, observation) in observations {
guard let observer = observation.observer else {
observations.removeValue(forKey: id)
continue
}
observer.dataDidUpdate(data)
}
}
static func addObserver<T: IsObserver>(_ observer: T) {
let id = ObjectIdentifier(observer)
let ob = Observation.init(observer: observer)
observations[id] = ob
}
static func removeObserver<T: IsObserver>(_ observer: T) {
let id = ObjectIdentifier(observer)
observations.removeValue(forKey: id)
}
}
更新: 好吧,最后还是到了。比我想象的要难,需要进行类型擦除。在这个要领中,有两个版本:第一个版本是根据原问题的关联类型协议的版本。不过它是有限的--作为观察者的对象只能观察一种类型。所以我做了另一个变体,它可以有多个类型,但不使用associatetype协议,所以观察者必须手动检查类型。
https:/gist.github.comxaphod4f8a6402429759b6b3fd8ea2d8ea53c4。
我将简化一下你的用例(忽略观察),希望能让你明白这个概念。
HasObservers
基本上有2个相关的类型--------------------------------。DataType
和 IsObserver
类型,然后你就会约束这个 IsObserver
型,才能有正确的 DataType
protocol IsObserver {
associatedtype DataType
func dataDidUpdate(_ data: [DataType])
}
protocol HasObservers {
associatedtype DataType
associatedtype ObserverType: IsObserver where ObserverType.DataType == DataType
static func addObserver(_ observer: ObserverType)
static func tellObserversDataDidUpdate(_ data: [DataType])
// ..
}