在Swift中编写一个共同的主题 - 观察者实现

时间:2016-12-15 17:55:10

标签: swift generics design-patterns

让我们说我有一个实现了美丽主题观察者模式的课程。 (这是Swift 3; Swift 2本质上没有什么不同。)

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() }
    }
}

(我采用惯用的Swift术语&#34;委托&#34;大致相当于设计模式概念&#34;观察者&#34;。)

上面的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类型上进行模板化,并在任何我们想让其他类充当Subject的地方继承它。相当简单。

协议,协议扩展和泛型似乎拥有这种代码重用所需的一些机制,但我无法解决如何实现它。

帮助?

1 个答案:

答案 0 :(得分: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> { }