Swift中的观察者模式

问题描述:

我想实现一个观察者模式,但是我没有在Swift(也是2.0)中找到正确的编程语言结构。主要问题是:

I want to implement an observer pattern, but I do not find the proper programming language constructs in Swift (also 2.0). The main problems are:


  1. protocol extension 不允许存储的属性。

  2. 在类中,我们可以添加存储的属性,但是我们不能强制子类覆盖它的一些继承方法。

  1. protocol and extension does not allow stored properties.
  2. In classes we could add stored properties, but we can not force a subclass to override some of its inherited methods.

这就是我想要的:

{class|protocol|extension|whathaveyou} Sensor {
    var observers = Array<Any>() // This is not possible in protocol and extensions 
    // The following is does not work in classes
    func switchOn() 
    func switchOff()
    var isRunning : Bool {
        get
    }
}

class LightSensor : Sensor {
    //...
    override func switchOn() {
        // turn the sensor on
    }
}

// In the class C, implementing the protocol 'ObserverProtocol'

var lightSensor = LightSensor()
lightSensor.switchOn()
lightSensor.registerObserver(self) // This is what I want

以下是我的知识:

class Sensor {
    private var observers = Array<Observer>()

    func registerObserver(observer:ObserverDelegate) {
        observers.append(observer)
    }
}

protocol SensorProtocol {
    func switchOn()
    func switchOff()
    var isRunning : Bool {
        get
    }
}

class LightSensor : Sensor, SensorProtocol {
    func switchOn() {
        //
    }
    func switchOff() {
        //
    }

    var isRunning : Bool {
        get {
            return // whatever
        }
    }
}

但这不是很方便,因为传感器 SensorProtocol 应该齐头并进,并且要求子类 LightSensor 必须满足。

But this is not very convenient, because both Sensor and SensorProtocol should come hand in hand, and are both requirements the subclass LightSensor has to fulfill.

任何想法?

协议是一套抽象的要求s共享了许多(可能非常不同的)其他对象。因此,将数据存储在协议中是不合逻辑的。这就像全球国家。我可以看到你想要定义观察者如何存储的规范。这也可以让你'删除'其他人'成为一个观察者,而且对观察者的存储方式也有很大限制。

A protocol is an abstract set of requirements shared across a number of (potentially very different) other objects. As such, it's illogical to store data in a protocol. That would be like global state. I can see that you want to define the specification for how the observers are stored though. That would also allow 'you' to remove 'someone else' from being an observer, and it's very restrictive about how the observers are stored.

所以,你的协议应该暴露添加和删​​除你自己作为观察者的方法。然后,实现协议的对象负责决定观察者的存储方式和位置,并实现添加和删除。

So, your protocol should expose methods to add and remove 'yourself' as an observer. It's then the responsibility of the object implementing the protocol to decide how and where the observers are stored and to implement the addition and removal.

您可以创建一个结构来使用您的协议,例如:

You could create a struct to work with your protocols, something like:

protocol Observer: class {
    func notify(target: Any)
}

protocol Observable {
    mutating func addObserver(observer: Observer)
    mutating func removeObserver(observer: Observer)
}

struct Observation: Observable {
    var observers = [Observer]()

    mutating func addObserver(observer: Observer) {
        print("adding")
        observers.append(observer)
    }
    mutating func removeObserver(observer: Observer) {
        print("removing")
        for i in observers.indices {
            if observers[i] === observer {
                observers.removeAtIndex(i)
                break
            }
        }
    }
    func notify(target: Any) {
        print("notifying")
        for observer in observers {
            observer.notify(target)
        }
    }
}

struct ATarget: Observable {
    var observation = Observation()

    mutating func addObserver(observer: Observer) {
        observation.addObserver(observer)
    }
    mutating func removeObserver(observer: Observer) {
        observation.removeObserver(observer)
    }

    func notifyObservers() {
        observation.notify(self)
    }
}

class AnObserver: Observer {
    func notify(target: Any) {
        print("notified!")
    }
}

let myObserver = AnObserver()
var myTarget: Observable = ATarget()
myTarget.addObserver(myObserver)

if let myTarget = myTarget as? ATarget {
    myTarget.notifyObservers()
}