热门问题
时间线
聊天
视角

观察者模式

設計模式 来自维基百科,自由的百科全书

观察者模式
Remove ads

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

Thumb
观察者模式的UML类图

参与类别

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

Thumb
观察者模式的样例UML类图和序列图[2]

抽象目标类别

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

  • 添附(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 所产生的变更。

Remove ads

示例

Java

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

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();
    }
}
Remove ads

C#

C#提供了IObservable[3]IObserver[4]接口,还有如何实现这个设计模式的文档[5]

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

from abc import ABC, abstractmethod

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

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

class Subject():
    def __init__(self):
        self._observers = []
    def register_observer(self, observer):
        self._observers.append(observer)
    def unregister_observer(self, observer):
        self._observers.remove(observer)
    def notify_observers(self, *args, **kwargs):
        for observer in self._observers:
            observer.update(self, *args, **kwargs)

其执行:

>>> subject = Subject()
>>> observer = ObserverA(subject)
>>> subject.notify_observers("test", kw="python")
Got ('test',) {'kw': 'python'} From <__main__.Subject object at 0x736310a21940>
Remove ads

引用

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads