有两种相互作用的泛型类集合是一种很好的设计模式。一个简单的例子是Observable-Observer模式。可观察的事件向观察者发布事件,但是无论观察到什么类型的事件,模式都是相同的。Swift中协议和泛型的限制
我的第一个想法是,首选的方法是定义两个通用协议。这应该提供最小的耦合,随着代码库的增长,这种耦合会变得很好。
protocol ProtocolObserver {
typealias EventType
func update<O:ProtocolObservable where O.EventType == EventType>(observable:O, event:EventType) -> Void
}
protocol ProtocolObservable {
typealias EventType
func registerObserver<O:ProtocolObserver where O.EventType == EventType>(observer:O) -> Bool
func unregisterObserver<O:ProtocolObserver where O.EventType == EventType>(observer:O) -> Void
}
试图定义实现上述协议的类竟然是一个受伤的世界。我没有找到任何方法来做到这一点。
然而,实现泛型基类将是一个可接受的解决方案。
protocol GenericObserver {
func update<EventType>(observable:GenericObservable<EventType>, event:EventType);
}
class GenericObservable<EventType> {
private var observers:[GenericObserver] = []
func registerObserver(observer:GenericObserver) -> Bool {
// Code to avoid registering the same observer twice
observers.append(observer)
return true
}
func unregisterObserver(observer:GenericObserver) -> Void {
// Code to remove the observer if present in observers
}
func notifyObservers(event:EventType) -> Void {
for observer in observers {
observer.update(self, event: event)
}
}
}
这次没有定义一些实现协议的类的问题。将它们添加到通用观察器的实例并未显示出我期望的行为。
let numberObservable = GenericObservable<NSNumber>()
class NumberObserver : GenericObserver {
func update<NSNumber>(observable:GenericObservable<NSNumber>, event:NSNumber) {
print("Number Event \(event)")
}
}
let numberObserver = NumberObserver()
numberObservable.registerObserver(numberObserver)
class DataObserver : GenericObserver {
func update<NSData>(observable:GenericObservable<NSData>, event:NSData) {
print("Data Event \(event)")
}
}
let dataObserver = DataObserver()
numberObservable.registerObserver(dataObserver)
numberObservable.notifyObservers(NSNumber(int: 42))
我预计numberObservable.registerObserver(dataObserver)
会导致编译错误。相反,它高兴地打印输出
Number Event 42
Data Event 42
这一切给我留下了两个问题:
我有什么误解,当我期望编译器不接受
numberObservable.registerObserver(dataObserver)
?有没有一种方法可以分别实现一对符合
ProtocolObserver
和ProtocolObservable
的类?
非常感谢你提供了这个非常有趣和有启发性的答案。是的,旧的C++程序员确实相信他以与实例化C++模板相同的方式引入了两种不同的类型。 只是为了澄清我的第二个问题的一点。 Swift不允许我使用'Observable'协议作为变量或函数参数。我是否正确地说,这使得我无法使用一对协议,例如我在示例中使用的'ProtocolObserver'和'ProtocolObservable'? –
是的,没有部分专业化是使用Swift访问C++开发人员的东西。请参阅[这个答案](http://stackoverflow.com/a/30483738/3925941)关于你不能使用'ProtocolObserver'作为参数的原因的更多信息,因为它有一个关联的类型。 –
@Airspeed你可以请解释一下,'observable.register(intReceiver.receiveInt)'工作如何?我相信这个方法接受一个函数(严格地说,指向代码段中的某个内存的指针),而不需要任何关联的数据。我错了吗? 'observable'如何捕获'intReceiver'来稍后调用一个方法? – slashdot