观察者模式

<image>

观察者模式（observer pattern），是一种软件设计模式。在此种模式中，一个目标物件管理所有相依于它的观察者物件，并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用在即时事件处理系统。

## 结构

<image>

在上面的UML类图中，`Subject`类不直接更新依赖对象的状态，`Subject`转而提及`Observer`接口（`update()`）来更新状态，这使得`Subject`独立于依赖对象的状态是如何更新的。`Observer1`和`Observer2`通过将自己的同步于主题的状态实现了`Observer`接口。

UML序列图展示了运行时交互：`Observer1`和`Observer2`对象调用`attach(this)`于`Subject1`之上来注册自身。假定`Subject1`的状态变更了，`Subject1`调用`notify()`于自身之上。`notify()`调用`update()`在已注册的`Observer1`和`Observer2`对象之上，它从`Subject1`要来变更了的数据（`getState()`）用于更新（同步）自身的状态。

### 参与者

参与本模式的各类别列出如下。成员函式以模拟的方式列出。

抽象目标类别，提供一个界面让观察者进行添附与解附作业。此类别内有个不公开的观察者串炼，并透过下列函式(方法)进行作业：

- 添附(Attach)：新增观察者到串炼内，以追踪目标物件的变化。
- 解附(Detach)：将已经存在的观察者从串炼中移除。
- 通知(Notify)：利用观察者所提供的更新函式来通知此目标已经产生变化。

添附函式包涵了一个观察者物件参数。也许是观察者类别的虚拟函式(即更新函式)，或是在非物件导向的设定中所使用的函式指标(更广泛来讲，函式子或是函式物件)。

目标类别，提供了观察者欲追踪的状态。也利用其源类别(例如前述的抽象目标类别)所提供的方法,来通知所有的观察者其状态已经更新。此类别拥有以下函式：

- 取得状态(GetState)：回传该目标物件的状态。

抽象观察者界面，是一个必须被实做的抽象类别。这个类别定义了所有观察者都拥有的更新用界面，此界面是用来接收目标类别所发出的更新通知。此类别含有以下函式：

- 更新(Update)：会被实做的一个抽象(虚拟)函式。

抽象观察者界面，含有指向目标类别的参考(reference)，以接收来自目标类别的更新状态。此类别含有以下函式：

- 更新(Update)：是前述抽象函式的实做。当这个函式被目标物件呼叫时，观察者物件将会呼叫目标物件的取得状态函式，来其所拥有的更新目标物件资讯。

每个观察者类别都要实做它自己的更新函式，以应对状态更新的情形。

当目标物件改变时，会通过呼叫它自己的通知函式来将通知送给每一个观察者物件，这个通知函式则会去呼叫已经添附在串炼内的观察者更新函式。通知与更新函式可能会有一些参数，好指明是目前目标物件内的何种改变。这么作将可增进观察者的效率(只更新那些改变部分的状态)。

## 用途

- 当抽象个体有两个互相依赖的层面时。封装这些层面在单独的物件内将可允许程序员单独地去变更与重复使用这些物件，而不会产生两者之间交互的问题。
- 当其中一个物件的变更会影响其他物件，却又不知道多少物件必须被同时变更时。
- 当物件应该有能力通知其他物件，又不应该知道其他物件的实做细节时。

观察者模式通常与MVC范式有关系。在MVC中，观察者模式被用来降低model与view的耦合程度。一般而言，model的改变会触发通知其他身为观察者的model。而这些model实际上是view。Java Swing就是个范例，示意了model 预期会透过PropertyChangeNotification架构以送出改变的通知给其他view。Model类别是Java bean类别的一员，并拥有与上述目标类别同样的行为。View类别则系结了一些GUI中的可视元素，并拥有与上述观察者类别同样的行为。当应用程序在执行时。使用者将因view做出相应的更新而看见model所产生的变更。

## 示例

### C++

下面是C++23实现：

```c++
import std;

using std::reference_wrapper;
using std::vector;

class Subject; // Forward declaration for usage in Observer

class Observer {
private:
    // Reference to a Subject object to detach in the destructor
    Subject& subject;
public:
    explicit Observer(Subject& subj):     
        subject{subj} {
        subject.attach(*this);
    }

    virtual ~Observer() {
        subject.detach(*this);
    }
  
    Observer(const Observer&) = delete;
    Observer& operator=(const Observer&) = delete;

    virtual void update(Subject& s) const = 0;
};

// Subject is the base class for event generation
class Subject {
private:
    vector<RefObserver> observers;
public:
    using RefObserver = reference_wrapper<const Observer>;
  
    // Notify all the attached observers
    void notify() {
        for (const Observer& x: observers) {
            x.get().update(*this);
        }
    }
  
    // Add an observer
    void attach(const Observer& observer) {
        observers.push_back(observer);
    }
  
    // Remove an observer
    void detach(Observer& observer) {
        observers.remove_if([&observer](const RefObserver& obj) -> bool { 
            return &obj.get() == &observer; 
        });
    }
};

// Example of usage
class ConcreteObserver: public Observer {
public:
    explicit ConcreteObserver(Subject& subj): 
        Observer(subj) {}
  
    // Get notification
    void update(Subject&) const override {
        std::println("Got a notification");
    }
};

int main(int argc, char* argv[]) {
    Subject cs;
    ConcreteObserver co1(cs);
    ConcreteObserver co2(cs);
    cs.notify();
}
```

程序的输出为：

```output
Got a notification
Got a notification
```

### Java

下面的Java例子接受键盘输入并将每个输入行作为一个事件来处理。当在一个字符串由`System.in`提供出来之时，方法`notifyObservers()`接着被调用，用来通知所有观察者这个事件发生了，这采用了调用它们的更新方法的形式。

```java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

interface Observer {
    void update(String event);
}
  
class EventSource {
    List<Observer> observers = new ArrayList<>();
  
    public void notifyObservers(String event) {
        observers.forEach(observer -> observer.update(event));
    }
  
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
  
    public void scanSystemIn() {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            notifyObservers(line);
        }
    }
}

public class ObserverDemo {
    public static void main(String[] args) {
        System.out.println("Enter Text: ");
        EventSource eventSource = new EventSource();
        
        eventSource.addObserver(event -> System.out.println("Received response: " + event));

        eventSource.scanSystemIn();
    }
}
```

### C#

C#提供了IObservable和IObserver接口，还有如何实现这个设计模式的文档。

```csharp
class Payload {
    internal string Message { get; init; }
}

class Subject : IObservable<Payload> {
    private readonly List<IObserver<Payload>> _observers = new List<IObserver<Payload>>();

    IDisposable IObservable<Payload>.Subscribe(IObserver<Payload> observer) {         
        if (!_observers.Contains(observer)) {
            _observers.Add(observer);
        }

        return new Unsubscriber(observer, _observers);
    }

    internal void SendMessage(string message) {
        foreach (var observer in _observers) {
            observer.OnNext(new Payload { Message = message });
        }
    }
}

internal class Unsubscriber : IDisposable {
    private readonly IObserver<Payload> _observer;
    private readonly ICollection<IObserver<Payload>> _observers;

    internal Unsubscriber(
        IObserver<Payload> observer,
        ICollection<IObserver<Payload>> observers) {
        _observer = observer;
        _observers = observers;
    }

    void IDisposable.Dispose() {
        if (_observer != null && _observers.Contains(_observer)) {
            _observers.Remove(_observer);
        }
    }
}

internal class Observer : IObserver<Payload> {
    private string _message;

    public void OnCompleted() {
    }

    public void OnError(Exception error) {
    }

    public void OnNext(Payload value) {
        _message = value.Message;
    }

    internal IDisposable Register(IObservable<Payload> subject) {
        return subject.Subscribe(this);
    }
}
```

### Python

下面是Python的例子：

```python
from abc import ABC, abstractmethod
from weakref import WeakValueDictionary

class Subject():
    def __init__(self):
        self.__observer_dict = WeakValueDictionary()
    def register(self, observer):
        self.__observer_dict[id(observer)] = observer
    def unregister(self, observer):
        del self.__observer_dict[id(observer)]
    def notify(self, *args, **kwargs):
        for key in self.__observer_dict:
            self.__observer_dict[key].update(self, *args, **kwargs)

class Observer(ABC):
    def __init__(self, subject):
        subject.register(self)
    @abstractmethod
    def update(self): pass

class ObserverA(Observer):
    def update(self, subject, *args, **kwargs):
        print("Got", args, kwargs, "From", subject)
```

其执行：

```pycon
>>> subject = Subject()
>>> observer1 = ObserverA(subject)
>>> observer2 = ObserverA(subject)
>>> subject.notify("test", kw="text")
Got ('test',) {'kw': 'text'} From <__main__.Subject object at 0x725f4bc71d30>
Got ('test',) {'kw': 'text'} From <__main__.Subject object at 0x725f4bc71d30>
```