Skip to content

Head First 设计模式 02-观察者模式

🏷️ 《Head First 设计模式》

观察者模式 定义了对象之间一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

出版者 + 订阅者 = 观察者模式

说起来这个和 MQ 的生产者、消费者的概念比较类似,Apollo 配置中心也有类似的模式,再比如前端框架中数据和视图之间的绑定。

大概的类图如下图所示。 Subject 提供注册(RegisterObserver)、删除(RemoveObserver)和通知(NotifyObservers)接口,Observer 是订阅者,提供更新(Update)接口。

Java 中有一个内置的观察者模式。可以使用 Observer 接口和 Observable 类,Observer 接口类似于上面类视图中的 Observer 接口,Observable 类则类似于上图中 Subject 接口。

设计原则

No.4

为了交互对象之间的松耦合设计而努力。

示例代码

Subject

csharp
public interface Subject
{
    void RegisterObserver(Observer observer);
    void RemoveObserver(Observer observer);
    void NotifyObservers();
}

Observer

csharp
public interface Observer
{
    void Update();
}

ConcreteSubject

csharp
public class ConcreteSubject : Subject
{
    List<ConcreteObserver> _observers = new List<ConcreteObserver>();

    string _status;
    public string Status {
        get
        {
            return _status;
        }
        set {
            _status = value;
            NotifyObservers();
        }
    }

    public void RegisterObserver(Observer observer)
    {
        if (observer is ConcreteObserver)
        {
            var concreteObserver = observer as ConcreteObserver;
            concreteObserver.Subject = this;
            _observers.Add(concreteObserver);
        }
    }

    public void RemoveObserver(Observer observer)
    {
        if (observer is ConcreteObserver)
        {
            var concreteObserver = observer as ConcreteObserver;
            concreteObserver.Subject = null;
            _observers.Remove(concreteObserver);
        }
    }

    public void NotifyObservers()
    {
        foreach (var observer in _observers)
        {
            observer.Update();
        }
    }
}

ConcreteObserver

csharp
public class ConcreteObserver : Observer
{
    public string _name;
    public ConcreteSubject Subject { get; set; }

    public ConcreteObserver(string name)
    {
        _name = name;
    }

    public ConcreteObserver(string name, ConcreteSubject subject)
    {            
        _name = name;

        subject.RegisterObserver(this);
    }


    public void Update()
    {
        Console.WriteLine($"{_name}:{Subject?.Status}");
    }
}

Program

csharp
class Program
{
    static void Main(string[] args)
    {
        ConcreteSubject subject = new ConcreteSubject();

        var observer1 = new ConcreteObserver("Observer 1");
        var observer2 = new ConcreteObserver("Observer 2", subject);
        var observer3 = new ConcreteObserver("Observer 3");

        subject.RegisterObserver(observer1);
        subject.RegisterObserver(observer3);

        subject.Status = "Running";

        subject.RemoveObserver(observer2);

        subject.Status = "Sleeping";

        Console.ReadLine();
    }
}