Head First 设计模式 02-观察者模式
观察者模式 定义了对象之间一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
出版者 + 订阅者 = 观察者模式
说起来这个和 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();
}
}