有兩種相互作用的泛型類集合是一種很好的設計模式。一個簡單的例子是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