2016-12-15 37 views
3

假設我有一個類實現了一個漂亮的主題觀察者模式。 (這是夫特3;夫特2將在本質上沒有什麼不同。)在Swift中編寫一個共同的主題觀察者實現

protocol Delegate : class 
{ 
    func method() 
} 

class Subject 
{ 
    private typealias WeakDelegate = WeakReference<Delegate> 
    private var nextAvailableDelegateId = 0 
    private var delegates = [ Int : WeakDelegate ]() 

    @discardableResult 
    public func addDelegate(_ delegate: Delegate) -> Int 
    { 
     let id = nextAvailableDelegateId 
     nextAvailableDelegateId += 1 
     delegates[ id ] = WeakDelegate(value: delegate) 
     return id 
    } 

    public func removeDelegate(_ idForDelegate: Int) 
    { 
     delegates.removeValue(forKey: idForDelegate) 
    } 

    fileprivate func eachDelegate(fn: (Delegate) -> Void) 
    { 
     for (key, weakDelegate) in delegates 
     { 
      // Has this weak delegate reference become nil? 
      // 
      guard let delegate = weakDelegate.value else 
      { 
       // Yes. Remove it. 
       delegates.removeValue(forKey: key) 
       continue 
      } 

      fn(delegate) 
     } 
    } 

    private func exampleNotifier() 
    { 
     eachDelegate{ $0.method() } 
    } 
} 

(我走了慣用夫特術語「委託」爲大致等同於所述設計圖案概念「觀察者」。)

以上WeakReference類型不是嚴格意義上講這個問題的一部分,但如果你很好奇:

public class WeakReference<T> 
{ 
    public var value: T? 
    { 
     return abstractValue as? T 
    } 

    public init(value: T) 
    { 
     abstractValue = value as AnyObject 
    } 

    private weak var abstractValue: AnyObject? 
} 

現在我想創建另一個類類似於Subject與其他代表協議類似於Delegate 。我如何在新類中使用我已經爲Subject編寫的實現?

一個答案是複製和粘貼代碼。不是一個好的答案。

在C++中,我們可以創建一個真正的mixin,一個包含實現Subject的所有代碼和數據的類,以泛型Delegate類型爲模板,並且在我們希望使其他類作爲學科。相當微不足道。

協議,協議擴展和泛型似乎有一些這種代碼重用所必需的機制,但我不知道如何實現它。

幫助?

+0

也許我誤解了,但是你不能從'Subject'繼承你的新類嗎? – sdasdadas

+0

@sdasdadas想象一下,我需要一對新的類,'NewSubject'和'NewDelegate'。問題是:如何繼承'Subject',使NewDelegate成爲新的委託類型,例如'eachDelegate()'接受一個帶有'NewDelegate'的函數? – OldPeculier

回答

0

您可以使用協議繼承和泛型從某些基本協議派生。

每一個新的代表將來自父類繼承:

protocol Delegate: class { 

    func method() 
} 

protocol DelegateA: Delegate { } 

protocol DelegateB: Delegate { } 

你父主題類可以使用通用的特性符合你的父母協議來實現。

class Subject<T: Delegate> { 

    private typealias WeakDelegate = WeakReference<T> 
    private var nextAvailableDelegateId = 0 
    private var delegates = [Int: WeakDelegate]() 

    @discardableResult 
    public func addDelegate(_ delegate: T) -> Int { 
     let id = nextAvailableDelegateId 
     nextAvailableDelegateId += 1 
     delegates[id] = WeakDelegate(value: delegate) 
     return id 
    } 

    public func removeDelegate(_ idForDelegate: Int) { 
     delegates.removeValue(forKey: idForDelegate) 
    } 

    fileprivate func eachDelegate(fn: (T) -> Void) { 
     for (key, weakDelegate) in delegates { 
      // Has this weak delegate reference become nil? 
      guard let delegate = weakDelegate.value else { 
       // Yes. Remove it. 
       delegates.removeValue(forKey: key) 
       continue 
      } 
      fn(delegate) 
     } 
    } 

    private func exampleNotifier() { 
     eachDelegate{ $0.method() } 
    } 
} 

每個新主題都可以實例化爲符合您孩子代表的通用標準。

class SubjectA<T: DelegateA>: Subject<T> { } 

class SubjectB<T: DelegateB>: Subject<T> { } 
+1

那麼,我希望這工作。但是你不能使用協議在Swift中實例化一個泛型。因此,您不能繼承'SubjectA',以便它可以在新的協議類型'DelegateA'上運行。你將不得不使用一個具體的類型(一些協議'DelegateA'的實現)來實例化SubjectA類,然後你已經擊敗了使用觀察者協議創建主題類的目的。請參閱http://stackoverflow.com/q/33503602/358475。 – OldPeculier

+0

@OldPeculier恐怕我還是不明白。當你實例化時,某些東西必須是具體的類型。我想也許這對我來說太抽象了,不能完全理解。你可以用'NewSubject'和'NewDelegate'實現一個例子嗎?我會在短時間內回答我的答案,以防有人能糾正它。 – sdasdadas

+1

@OldPeculier啊,我現在明白我已經多了一點時間了。我認爲擴展會繞過它,但似乎這些問題完全在於你不能使用協議來符合通用參數。希望我能幫助更多! – sdasdadas