设计模式(二十)—— 观察者模式
模式简介
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并更新。
观察者模式又叫发布-订阅模式,主要描述了一种目标与观察者之间的相互关系。目标对象一旦发生变化,它所有的观察者都得到通知并作出相应的更新操作。下图恰好描述了这种场景,目标对象拿出烟,观察者纷纷掏出火柴帮忙点烟。
结构分析
UML类图
角色说明
- Subject
目标类。提供删除、添加观察者的方法,当它的状态发生变化时,向它的观察者发出通知。
- Observer
观察者。为具体观察者提供一个统一的更新接口。
- ConcreteObserver
具体观察者。实现更新接口,使自身状态与目标一致。
工作原理
当目标对象发生改变时,它将通知所有观察者,观察者得到通知后访问目标对象更新状态。
结构代码
//目标类
public class Subject
{
private List<Observer> _observers = new List<Observer>();
private int _state;
public int GetState()
{
return _state;
}
public void SetState(int state)
{
_state = state;
Notify();
}
public void Attach(Observer observer)
{
if (!_observers.Contains(observer))
{
_observers.Add(observer);
}
}
public void Detach(Observer observer)
{
if (_observers.Contains(observer))
{
_observers.Remove(observer);
}
}
public void Notify()
{
foreach (var observer in _observers)
{
observer.Update();
}
}
}
//观察者
public abstract class Observer
{
protected Subject _subject;
public abstract void Update();
}
//具体观察者A
public class ConcreteObserverA : Observer
{
public ConcreteObserverA(Subject subject)
{
_subject = subject;
subject.Attach(this);
}
public override void Update()
{
Console.WriteLine($"ConcreteObserverA Update State:{_subject.GetState()}");
}
}
//具体观察者B
public class ConcreteObserverB : Observer
{
public ConcreteObserverB(Subject subject)
{
_subject = subject;
subject.Attach(this);
}
public override void Update()
{
Console.WriteLine($"ConcreteObserverB Update State:{_subject.GetState()}");
}
}
//具体观察者C
public class ConcreteObserverC : Observer
{
public ConcreteObserverC(Subject subject)
{
_subject = subject;
subject.Attach(this);
}
public override void Update()
{
Console.WriteLine($"ConcreteObserverC Update State:{_subject.GetState()}");
}
}
//客户端调用
class Program
{
static void Main(string[] args)
{
Subject subject = new Subject();
ConcreteObserverA a = new ConcreteObserverA(subject);
ConcreteObserverB b = new ConcreteObserverB(subject);
ConcreteObserverC c = new ConcreteObserverC(subject);
subject.SetState(200);
Console.ReadLine();
}
}
程序输出
示例分析
本节模拟开篇描述的场景,女演员(目标对象)拿出烟,男演员(观察者)为其点烟。首先创建女演员类,包含一个Observer集合用来保存观察者,使用_state字段模拟女演员状态的变化,提供SetState以及GetState存取该状态,并提供Attach和Detach方法添加或删除观察者。
public class Actress
{
private List<Observer> _observers = new List<Observer>();
private int _state;
public int GetState()
{
return _state;
}
public void SetState(int state)
{
_state = state;
Notify();
}
public void Notify()
{
foreach (var observer in _observers)
{
observer.LightCigarette();
}
}
public void Attach(Observer observer)
{
if (!_observers.Contains(observer))
{
_observers.Add(observer);
}
}
public void Detach(Observer observer)
{
if (_observers.Contains(observer))
{
_observers.Remove(observer);
}
}
}
创建观察者,分别实现3个具体观察者。
public abstract class Observer
{
protected Actress _actress;
public abstract void LightCigarette();
}
public class ActorA : Observer
{
public ActorA(Actress actress)
{
_actress = actress;
actress.Attach(this);
}
public override void LightCigarette()
{
Console.WriteLine($"ActorA light the cigarette");
}
}
public class ActorB : Observer
{
public ActorB(Actress actress)
{
_actress = actress;
actress.Attach(this);
}
public override void LightCigarette()
{
Console.WriteLine($"ActorB light the cigarette");
}
}
public class ActorC : Observer
{
public ActorC(Actress actress)
{
_actress = actress;
actress.Attach(this);
}
public override void LightCigarette()
{
Console.WriteLine($"ActorC light the cigarette");
}
}
客户端调用
class Program
{
static void Main(string[] args)
{
Actress actress = new Actress();
ActorA a = new ActorA(actress);
ActorB b = new ActorB(actress);
ActorC c = new ActorC(actress);
actress.SetState(1);
Console.ReadLine();
}
}
程序输出
适用场景
-
当一个对象的改变需要同时改变其它对象,而又不知道具体有多少对象时。
-
当一个对象必须通知其他对象,而它不知道其他对象是谁。
-
但一个抽象模型有两个方面,其中一个方面依赖于另一个方法。将二者封装在独立的对象中以使它们各自独立地改变和重用。