The Programming world of Alex

设计模式之Observer模式

引例:
银行现在的业务大多有提醒业务,比如我们用信用卡消费的时候银行会有短信通知和Email通知等方法立即提醒客户账户发生了变化。这就是典型的Observer模式,A(账户)发生变化之后通知B(手机)和C(Email),以后也许还会通知D(电话)等等。。。

程序设计中也会遇到很多这样的问题,比如说MFC中的Document/View架构,Document中的数据变化会立即通知View的显示也相应变化,View的显示变化后也会通知Document中的数据产生对应变化;再比如回调函数,触发某个事件后通知调用回调函数。但凡“通知依赖”问题大都可以用到Observer模式。

动机:
为某些对象建立“通知依赖关系”——“一个对象的状态发生改变,那么与之相关的所有对象都要改变”。
显然这种关系是紧耦合的,为保证这种结构在遇到变化时能够比较稳定,我们必须使之松耦合。

意图:
定义对象间的一种一对多关系,以便当一个对象的状态发生改变时,所有依赖它的对象都得到通知和自动更新(GoF23)

设计思路:
我们的目的是在A的状态发生改变时会自动通知B,上下两幅图分别代表了两个设计的方法。

上图是一种较容易想到的解决方法,但是可以看出A依赖于B,两者是紧耦合关系。
OO中有一个重要的原则就是“依赖倒置原则”,于是就有了下图:
接口IA依赖于接口IB,而IA和IB是从A,B中抽象出来的相对稳定的部分,IA和IB之间的依赖关系相对稳定,不易变化。

Ok,就是这么简单!Observer模式的思想就是这样!问题的关键在于如何抽象IA和IB,下面是GoF23对Observer模式描述的UML图

其中Subject即接口IA,Observer即接口IB。
Observer只有一个方法Update,用于更新具体的Observer。
Subject一般有一个List用于保存Observer的信息;Attach负责添加Observer;Detach负责删除Observer;Notify通知List中的所有Observer调用Update。


关于内存释放:
需要注意的是在ISubject的析构函数中清空List之前,必须首先释放其中每个指针的内存

 自己测试用的代码,仅供参考
  1//////////////////////////////////////////////////////////////////////////
  2//ObserverTest For Observer Pattern
  3//
  4//////////////////////////////////////////////////////////////////////////
  5
  6#include "stdafx.h"
  7#include "iostream"
  8#include <string>
  9#include <list>
 10using namespace  std;
 11
 12//账户参数
 13struct  AccountArgs
 14{
 15    string email;
 16    string phoneNum;
 17}
;
 18
 19//IObserver接口
 20class IObserver
 21{
 22public:
 23    virtual void Update(AccountArgs args) = 0;
 24}
;
 25
 26//具体类实现IObserver接口——Email
 27class Emailer : public IObserver
 28{
 29public:
 30    void Update(AccountArgs args)
 31    {
 32        string toAddress = args.email;
 33        cout<<"Email 通知:"<<args.email<<endl;
 34    }

 35}
;
 36
 37//具体类实现IObserver接口——Phone
 38class Mobile : public IObserver
 39{
 40public:
 41    void Update(AccountArgs args)
 42    {
 43        string phoneNumber = args.phoneNum;
 44        cout<<"手机 通知:"<<args.phoneNum<<endl;
 45    }

 46}
;
 47
 48//ISubject接口,抽象类
 49class ISubject
 50{
 51protected:
 52    //"一对多关系",可能有多个观察者
 53    list<IObserver*> observerList;
 54protected:
 55    //notify,addObserver,removeObserver为稳定的方法,提取出来
 56    virtual void notify(AccountArgs args) = 0;
 57
 58    void addObserver(IObserver* observer)
 59    {
 60        observerList.push_back(observer);
 61    }

 62
 63    bool removeObserver(IObserver* observer)
 64    {
 65        list<IObserver*>::iterator itr;
 66        for (itr = observerList.begin();itr!=observerList.end();itr++)
 67        {
 68            if (*itr == observer)
 69            {
 70                delete *itr;
 71                observerList.erase(itr);
 72                return true;
 73            }

 74        }

 75        return false;
 76    }

 77
 78    //析构函数
 79    ~ISubject()
 80    {
 81        //首先释放指针,之后清空List
 82        list<IObserver*>::iterator itr;
 83        for (itr = observerList.begin();itr!=observerList.end();itr++)
 84        {
 85            if ((*itr)!=NULL) { delete (*itr); }
 86        }

 87        observerList.clear();
 88    }

 89}
;
 90
 91//账户类,实现ISubject接口功能
 92class BankAccount: public ISubject
 93{
 94public:
 95    BankAccount()
 96    {
 97        addObserver(new Emailer());
 98        addObserver(new Mobile());
 99    }

100
101    void notify(AccountArgs args)
102    {
103        for(list<IObserver*>::iterator itr = observerList.begin();itr!=observerList.end();itr++)
104        {
105            (*itr)->Update(args);
106        }

107    }

108
109    //提款方法——通知Observer
110    void withDraw()
111    {
112        //////////////////////////////////////////////////////////////////////////
113        //提款操作.
114        //////////////////////////////////////////////////////////////////////////
115
116        //Observer的一些参数
117        AccountArgs args;
118        args.email = "qudeqing@126.com";
119        args.phoneNum = "1395517XXXX";
120        notify(args);            
121    }

122
123}
;
124
125int _tmain(int argc, _TCHAR* argv[])
126{
127    BankAccount bankAccount;
128    bankAccount.withDraw();
129    return 0;
130}

posted on 2009-04-05 22:51 Alex@VCC 阅读(1732) 评论(3)  编辑 收藏 引用 所属分类: 设计模式

评论

# re: 设计模式之Observer模式 2009-04-06 10:13 星绽紫辉

非常感谢!设计模式其实非常重要,希望斑竹出更多更好的设计模式的文章。  回复  更多评论   

# re: 设计模式之Observer模式 2009-05-08 12:33 brightcoder

牛人太多了.....  回复  更多评论   

# re: 设计模式之Observer模式 2010-04-30 10:35 calix

楼主这么写 不合逻辑吧?
BankAcount 不保存用户信息?


class BankAccount:public Isubject{
public:
void notify(account &person){
for(vector<Iobserver*>::iterator it=Observer.begin();it!=Observer.end();it++){
(*it)->update(person);
}
}
BankAccount(int num,string str){
add(new email);
add(new phone);
person.email=str;
person.phonename=num;

}
void withdraw(){
// account one={1,"2"};
notify(person);
}
private:
account person;

};  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(5)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜