设计模式 笔记 观察者模式 Observer
//---------------------------15/04/27----------------------------
//Observer 观察者模式----对象行为型模式
/*
1:意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2:别名:
依赖(Dependents),发布-订阅(Publish-Subscribe)
3:动机:
4:适用性:
1>当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这两者封装在独立的对象中以使它们可以各自独立
地改变和复用。
2>当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
3>当一个对象必须通知其他对象,而它又不能假定其他对象是谁。
5:结构:
Subject:
observers-------------------------->Observer:
Attach(Observer) Update()
Detach(Observer) |
Notify() |
{ for all o in observers |
{ o->Update()} |
} |
| |
| ConcreteObserver:
ConcreteSubject:<-------------------subject
GetState() Update()
{ return subjectState} { observerState = subject->GetState()}
SetState() observerState
subjectState
6:参与者:
1>Subject:
1)目标知道它的观察者。可以有任意多个观察者观察同一目标。
2)提供注册和删除观察者对象的接口。
2>Observer:
为那些在目标发生改变时需获得通知的对象定义一个更新接口。
3>ConcreteSubject:
1)将有关状态存入各ConcreteObserver对象。
2)当它的状态发生改变时,向它的各个观察者发出通知。
4>ConcreteObserver:
1)维护一个指向ConcreteSubject对象的引用。
2)存储有关状态,这些状态应与目标的状态保持一致。
3)实现Observer的更新接口以使自身状态与目标的状态保持一致。
7:协作:
1>当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
2>在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver
使用这些信息以使它的状态与目标对象的状态一致。
8:效果:
1>优点:
1)目标和观察者间的抽象耦合:
一个目标所知道的仅仅是它有一系列的观察者,每个都符合抽象的Observer类的简单接口。
目标不知道任何一个观察者属于哪个具体的类。这样的耦合关系时最小的。
2)支持广播通信:
不像通常的请求,目标发送的通知不需要指定它的接受者,通知被自动广播给所有已向该目标对象登记
的有关对象。
2>缺点:
意外的更新:
因为观察者并不知道其他观察者的存在,它可能对改变目标的最终代价一无所知。在目标上一个看似无害
的操作可能可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。
9:实现:
1>创建目标到其观察者之间的映射:
最简单的方式是在目标中存储观察者的指针,但是如果目标很多而观察者较少时,这样的存储代价太高,
所以可以用时间换空间,也就是使用一个关联查找机制(比如hash表)来维护目标到观察者的映射,这样
会增加访问观察者的开销。
2>观察多个目标:
如果要观察多个目标,必须扩展Update操作,加入一个参数,观察者知道应该检查哪一个目标。
3>谁触发更新:
1)目标:
由目标对象的状态设定操作在改变目标对象的状态后自动调用Notify,这样做的
优点是:客户不需要记住要在目标对象上调用Notify,
缺点是:多个连续的操作会产生多次连续的更新,造成较低的效率。
2)客户:
优点是:客户可以在做完一系列操作后再进行更新,效率更高,
缺点是:客户可能会忘记更新而造成错误。
4>对已删除的目标的悬挂引用:
当目标被删除时,观察者还保持着对目标的引用,因此会造成悬挂的情况,所以最好的做法是发送一个
通知,让观察者把指针设置为空。
5>在发出通知前确保目标的状态自身是一致的:
子类重定义一些操作时,可能造成先行通知(先调用基类的方法,这时已经通知过了),然后自己又改变了
状态。这样自身的状态前后是不一致的,所以避免这样的情况是模版方法:也就是在基类中使用一个non_virtual
的函数调用virtual函数,并在最后调用Notify,子类只能重新定义那个virtual函数,这样不管子类怎么改
最后都是会调用Notify的。
6>避免特定于观察者的更新协议:
1)目标在通知观察者的时候,传递了大量的信息(也就是Update的参数需要很多),这样使得观察者难以复用
这是因为Update参数的限制。
2)什么都信息都不传递,这样观察者需要付出大代价来知道什么东西改变了。
7>显式地指定感兴趣的改变:
可以让观察者注册自己感兴趣的事件,只有感兴趣的事件发生时,目标才会通知观察者。
8>封装复杂的更新语义:
依赖一个ChangeManager来维护目标和观察者之间的关系,它有三个责任:
1)它将一个目标映射到它的观察者并提供一个接口来维护这个映射,这样就不需要由目标来维护对其观察者
的引用。
2)它定义一个特定的更新策略。
3)根据一个目标的请求,它更新所有依赖于这个目标的观察者。
其实这就是一个中介者(Mediator)
10:代码示例: */
//必须先声明是类才能声明一个List存放指针。
class Subject;
//观察者:
class Observer
{
public:
virtual ~Observer();
virtual void Update(Subject* theChangedSubject) =
;
protected:
Observer();
};
//目标:
class Subject
{
public:
virtual ~Subject();
virtual void Attach(Observer*);
virtual void Detach(Observer*);
virtual void Notify();
protected:
Subject();
private:
List<Observer*>* _observers;
};
//绑定观察者
void Subject::Attach(Observer* o)
{
_observers->Append(o);
}
//卸载观察者
void Subject::Detach(Observer* o)
{
_observers->Remove(o);
}
//通知所有观察者
void Subject::Notify()
{
ListIterator<Observer*> i(_observers);
for(i.First(); !i.IsDone(); i.Next())
{
i.CurrentItem()->Update(this);
}
}
//一个ConcreteSubject
class ClockTimer :
public Subject
{
public:
ClockTimer();
virtual int GetHour();
virtual int GetMinute();
virtual int GetSecond();
void Tick();
};
void ClockTimer::Tick()
{
//时间的变化。。。
Notify();
}
//ConcreteObserver
class DigitalClock:
public Widget, public Observer
{
public:
DigitalClock(ClockTimer*);
virtual ~DigitalClock();
virtual void Update(Subject*);
virtual void Draw();
private:
ClockTimer* _subject;
};
//注册自己
DigitalClock::DigitalClock(ClockTimer* s)
{
_subject = s;
_subject->Attach(this);
}
//卸载自己
DigitalClock::~DigitalClock()
{
_subject->Detach(this);
}
//Update操作,调用了Draw
void DigitalClock::Update(Subject* theChangedSubject)
{
if(theChangedSubject == _subject)
Draw();
}
//画出时间
void DigitalClock::Draw()
{
int hour = _subject->GetHour();
int minute = _subject->GetMinute();
//在窗口中根据时间画出数字钟
}
//另外一个钟
class AnalogClick :
public Widget, public Observer
{
public:
AnalogClick(ClockTimer*);
virtual void Update(Subject*);
virtual void Draw();
};
//使用:
ClockTimer* timer =
new ClockTimer;
AnalogClick* analogClick =
new AnalogClick(timer);
DigitalClock* digitalClock =
new DigitalClock(timer);
//一旦timer时间更新,这两个时钟都会被通知,然后调用自己取得时间,并画出来。
设计模式 笔记 观察者模式 Observer的更多相关文章
- 乐在其中设计模式(C#) - 观察者模式(Observer Pattern)
原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:weba ...
- 8.5 GOF设计模式四: 观察者模式Observer
GOF设计模式四: 观察者模式Observer 现实中遇到的问题 当有许多不同的客户都对同一数据源感兴趣,对相同的数据有不同的处理方式,该如 何解决?5.1 定义: 观察者模式 观察者模式 ...
- 人人都会设计模式:观察者模式--Observer
https://segmentfault.com/a/1190000012295887 观察者模式是抽像通知者和观察者,达到具体通知者跟具体观察者没有偶合.能达到不管是切换通知者,或者是切换观察者,都 ...
- 二十四种设计模式:观察者模式(Observer Pattern)
观察者模式(Observer Pattern) 介绍定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例有一个Message实体类,某些对象 ...
- [设计模式] 19 观察者模式 Observer Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.当一个 ...
- c#设计模式之观察者模式(Observer Pattern)
场景出发 一个月高风黑的晚上,突然传来了尖锐的猫叫,宁静被彻底打破,狗开始吠了,大人醒了,婴儿哭了,小偷跑了 这个过程,如果用面向对象语言来描述,简单莫过于下: public class Cat { ...
- JAVA设计模式之观察者模式 - Observer
有趣的事情发生时,可千万别错过了!有一个模式可以帮你的对象知悉现况,不会错过该对象感兴趣的事.对象甚至在运行时可决定是否要继续被通知.有了观察者,你将会消息灵通. 介绍 观察者模式的定义: 在对象之间 ...
- 设计模式之观察者模式(Observer pattern)
最近参加了一次面试,其中笔试题有一道编程题,在更换掉试题的描述场景后,大意如下: 上课铃声响起,学生A/B/C/D进入教室:下课铃声响起,学生A/B/C/D离开教室. 要求使用设计模式的思想完成铃与学 ...
- 设计模式之观察者模式(Observer)
观察者模式原理:当有新的消息产生时发送给观察者,和中介者模式的不同地方是中介者模式强调中介的作用以及中介双方的交互,观察者模式是主动调用观察者成员函数进行消息发送. 代码如下: #include &l ...
随机推荐
- man -k : nothing appropriate.
➜ workplace man -k zip zip: nothing appropriate. 出现这种情况,是索引库没有建立. man 和 whatis 共用一个索引库的. 我们使用 man w ...
- 如何使用EditPlus批量删除 带有某个字符的一行
比如以下五行,我要将带有英文字母a的一行全部批量删除1234551243243123aa244123123981232137aa 2013-04-11 19:32 提问者采纳 我这里是英文版, ...
- php框架安装
安装yii框架 跳转到composer.phar目录 cd C:\ProgramData\ComposerSetup\bin 安装yii2高级版 php composer.phar create-pr ...
- 团队作业——Alpha冲刺 5/12
团队作业--Alpha冲刺 冲刺任务安排 杨光海天 今日任务:编辑界面完成部分内容,学习了下拉菜单控件的建立,完善界面标题内容,以及交互. 明日任务:继续完善编辑界面,学习使用gallery,着手配图 ...
- 线程同步方式之互斥量Mutex
互斥量和临界区非常相似,只有拥有了互斥对象的线程才可以访问共享资源,而互斥对象只有一个,因此可以保证同一时刻有且仅有一个线程可以访问共享资源,达到线程同步的目的. 互斥量相对于临界区更为高级,可以对互 ...
- Sublime2 DocBlocker插件在自动补全注释时输出自定义作者和当前时间等信息
Sublime在进行前端开发时非常棒,当然也少不了众多的插件支持,DocBlocker是在Sublime平台上开发一款自动补全代码插件,支持JavaScript (including ES6), PH ...
- php header函数导出excel表格
推荐一个除了用PHPExcel导出表格之外的另外一种比较简单不需要引入类文件的表格导入方法——header()导出excel表格. 导出表格的步骤封装成了方法,以便于重复使用,代码如下: /** * ...
- oracle中over函数
1.oracle中按一个字段分组排序后取第一条数据. SELECT * FROM (SELECT ROW_NUMBER() OVER(PARTITION BY 分组字段 ORDER BY 排序字符 D ...
- 企业案例--生产环节更改mysql字符集
查看数据库字符集: show database create dbname \G; 查看数据库表字符集: show table create tbname \G; 查看现有数据库字符集设置: show ...
- opencv——对象计数
思路: 1.通过形态学操作.阈值处理.距离变换等方法,使得各个轮廓分开 2.计算轮廓数量 #include <opencv2/opencv.hpp> #include <iostr ...