观察者模式定义了对象之间一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
2.2观察者模式UML类图:
一个观察者只有一个主题 |
一个主题对应多个观察者 |
<<Interface>> Subject
RegisterObserver() RemoveObserver() NotifyObservers() |
ConcreteSubject
RegisterObserver(){…} RemoveObserver(){…} NotifyObservers(){…} |
<<Interface>> Observer
Update() |
ConcreteObserver
Update(){…} |
一个观察者只有一个主题 |
一个主题对应多个观察者 |
<<Interface>> Subject
RegisterObserver() RemoveObserver() NotifyObservers() |
ConcreteSubject
RegisterObserver(){…} RemoveObserver(){…} NotifyObservers(){…} |
<<Interface>> Observer
Update() |
ConcreteObserver
Update(){…} |
一个观察者只有一个主题 |
一个主题对应多个观察者 |
<<Interface>> Subject
RegisterObserver() RemoveObserver() NotifyObservers() |
ConcreteSubject
RegisterObserver(){…} RemoveObserver(){…} NotifyObservers(){…} |
<<Interface>> Observer
Update() |
ConcreteObserver
Update(){…} |
2.3应用场景
现实世界中的报纸和订阅者之间的模式是一个最好的观察者模式。我们的报刊(Subject)一有更新就会发通知(送报纸)给所有报刊订阅人(Observers)。
2.4观察者模式分析与实现(c#描述)
//主题接口
public interface ISubject
{
void RegisterObserver(IObserver observer);
void RemoveObserver(IObserver observer);
void NotifyObservers();
}
//观察者接口
public interface IObserver
{
void Update(string astg_MsgFromSubject);
}
//主题实现类
public class Subject : ISubject
{
private ArrayList ial_Observers = new ArrayList();
private string _SubjectInfo;//主题更新信息
public string SubjectInfo
{
get { return _SubjectInfo; }
set {
_SubjectInfo = value;
this.NotifyObservers();//通知观察者
}
}
public void RegisterObserver(IObserver observer)
{
if (this.ial_Observers.IndexOf(observer) < 0)
{
this.ial_Observers.Add(observer);
}
}
public void RemoveObserver(IObserver observer)
{
if (this.ial_Observers.IndexOf(observer) > -1)
{
this.ial_Observers.Remove(observer);
}
}
public void NotifyObservers()
{
for (int lint_LoopCount = 0; lint_LoopCount < this.ial_Observers.Count; lint_LoopCount++)
{
((IObserver)this.ial_Observers[lint_LoopCount]).Update(this.SubjectInfo);
}
}
}
//观察者实现类
public class Observer : IObserver
{
private string istg_Info;
public Observer(string astg_Info)
{
this.istg_Info = astg_Info;
}
public void Update(string astg_MsgFromObject)
{
Console.WriteLine("更新观察者:" + this.istg_Info + " 这是来自主题的消息:" + astg_MsgFromObject);
}
}
//调用类
public class Subject_Observers_Test
{
public static void Do()
{
Subject lobj_Subject = new Subject();
//注册观察者1
IObserver lobj_Observer1 = new Observer("1号");
lobj_Subject.RegisterObserver(lobj_Observer1);
//注册观察者2
Observer lobj_Observer2 = new Observer("2号");
lobj_Subject.RegisterObserver(lobj_Observer2);
//通知观察者
lobj_Subject.SubjectInfo = "今天是星期天。";
//撤消观察者1
lobj_Subject.RemoveObserver(lobj_Observer1);
//再次通知观察者
lobj_Subject.SubjectInfo = "现在是下午3点钟。";
}
}
至此,观察者模式完毕。
观察者模式体现了上述的面向对象设计的几个原则,下面重点强调一下其中之一:为交互对象之间的松耦合设计而努力。
交互对象这里对应的就是主题和观察者。之所以说主题和观察者之间的关系是松耦合的,这是因为:关于观察者的一切,主题只知道观察者实现了某一个接口,主题依赖的是观察者的接口,而不是具体的观察者实现。另外,由于是观察者实现了接口,则程序运行的任何时候,我们都可以动态的增减观察者(前提是必须有指向当前主题对象的引用,则可以为该主题对象动态的增减观察者),而主题代码不需要作任何变动,而不是在编译之前就决定了只能通知哪些观察者。改变主题和观察者之间的任何一方,互相对对方不造成任何影响,这就是主题和观察者之间的松耦合关系。
同样,观察者模式也有其不是令人非常满意的地方。观察者模式中观察者获取数据的方式为被动的接受主题的通知,而主题只在全部数据更新后才一次性通知观察者数据要更新了。这样有可能不太方便,因为如果某些观察者只希望要主题的一部分数据,就没有必要被动等主题通知才获得数据,则想要产生一种主动提要求获得数据的方法。前者称之为推模式,后者称之为拉模式。这两种模式各有各的好处,但后者需要将主题数据暴露给观察者,这种方式不太好,但仍可根据实际情况具体考虑。