首页 > 代码库 > 【ThinkingInC++】76、设计模式

【ThinkingInC++】76、设计模式

第十章 设计模式

 

10.3 简化习语

 

10.3.1 信使

 

他将消息封装到一个对象中到处传递,而不是将消息的所有片段分开进行传递。

 

MessengerDemo.cpp

 

/**
* 书本:【ThinkingInC++】 MessengerDemo.cpp 
* 功能:将消息封装到一个对象中到处传递
* 时间:2014年10月29日17:54:53
* 作者:cutter_point
*/

#include <iostream>
#include <string>

using namespace std;

class Point //把这个类作为存放消息的信使
{
public:
    int x, y, z;    //他们就是存放信息的变量,只是一个搬运工
    Point(int xi, int yi, int zi) : x(xi), y(yi), z(zi) {}  //构造函数
    Point(const Point& p) : x(p.x), y(p.y), z(p.z) {}   //复制构造函数
    Point& operator=(const Point& rhs)
    {
        x=rhs.x;
        y=rhs.y;
        z=rhs.z;

        return *this;
    }
    friend ostream& operator<<(ostream& os, const Point& p)
    {
        return os<<"x="<<p.x<<" y="<<p.y<<" z="<<p.z<<endl;
    }
};

//这也是一个信使
class Vector
{
public:
    int magnitude, direction;
    Vector(int m, int d) : magnitude(m), direction(d) {}
};

class Space
{
public:
    //这里定义个静态函数,可以不用定义这个类的对象就调用这个函数
    static Point translate(Point p, Vector v)
    {
        //把每个对象都加上v的两个数据成员
        p.x+=v.magnitude+v.direction;
        p.y+=v.magnitude+v.direction;
        p.z+=v.magnitude+v.direction;

        return p;
    }
};

int main()
{
    Point p1(1, 2, 3);
    Point p2=Space::translate(p1, Vector(11, 47));
    cout<<"p1: "<<p1<<"p2: "<<p2<<endl;

    return 0;
}



 

10.4 单件

 

单件的一种变体将一个对象的“单件属性”从其实现中分离出来方法

 

静态函数

 

http://blog.csdn.net/zhangjieting/article/details/5930004

 

静态成员函数是类的成员函数,该函数不属于该类申请的任何一个对象,而是所有该类成员共同共有的一个函数。

 

和静态数据成员一样,静态成员函数是类的一部分,而不是对象的一部分。如果要在类外调用公用的静态成员函数,要用类名和域运算符“∷”。如

Box∷volume( );

实际上也允许通过对象名调用静态成员函数,如

a.volume( );

但这并不意味着此函数是属于对象a的,而只是用a的类型而已。

静态成员函数的作用是为了能处理静态数据成员。

可以说,静态成员函数与非静态成员函数的根本区别是: 非静态成员函数有this指针,静态成员函数并不属于某一对象,它与任何对象都无关,静态成员函数没有this指针。由此决定了静态成员函数不能访问本类中的非静态成员。

在C++程序中,静态成员函数主要用来访问静态数据成员,而不访问非静态成员。

 

假如在一个静态成员函数中有以下语句:

cout<<height<<endl;             //若height已声明为static,则引用本类中的静态成员,合法

cout<<width<<endl;              //若width是非静态数据成员,不合法

 

CuriousSingleton.cpp

 

/**
* 书本:【ThinkingInC++】 CuriousSingleton.cpp
* 功能:将一个对象的“单件属性”从其实现中分离出来方法
* 时间:2014年10月29日17:55:29
* 作者:cutter_point
*/

#include <iostream>

using namespace std;

template<class T>
class Singleton
{
    Singleton(const Singleton&);    //复制构造函数
    Singleton& operator=(const Singleton&); //这是赋值运算符
protected:
    Singleton() {}  //构造函数
    virtual ~Singleton() {}
public:
    static T& instance()    //静态函数,等待调用的时候
    {
        static T theInstance;   //创建一个T 的对象
        return theInstance;     //返回他
    }
};

class MyClass : public Singleton<MyClass>   //重Singleton<MyClass>派生出MyClass
{
    int x;
protected:
    friend class Singleton<MyClass>;    //把Singleton<myClass>声明为友元,上面的T使用
    MyClass() { x=0; }
public:
    void setValue(int n) { x=n; }
    int getValue() { return x; }
};

int main()
{
    MyClass& m=MyClass::instance(); //这个是继承来的
    cout<<m.getValue()<<endl;
    m.setValue(998);
    cout<<m.getValue()<<endl;

    return 0;
}


 

 

10.5  命令:选择操作

 

利用命令模式消除与事件处理的耦合

 

命令模式:将一个请求封装为一个对象,从而使我们可用不同的请求对可以进行参数化,对请求排队或者记录请求日志以及支持可撤销的操作 

 

http://blog.csdn.net/lcl_data/article/details/9080909

 

我们去餐厅吃饭,我们是通过服务员来点菜,具体是谁来做这些菜和他们什么时候完成的这些菜,其实我们都不知道。抽象之,“菜单请求者”我们和“菜单实现者”厨师,2者之间是松耦合的,我们对这些菜的其他一些请求比如“撤销,重做”等,我们也不知道是谁在做。其实这就是本文要说的Command模式。

        将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

 

 

 

 

 

MulticastCommand.cpp

 

/**
* 书本:【ThinkingInC++】
* 功能:设计模式之命令模式
* 时间:2014年10月29日17:56:02
* 作者:cutter_point
*/

#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <cstdlib>

//#define CLOCKS_PER_SEC  1000

using namespace std;

class Task
{
public:
    virtual void operation()=0;    //抽象类,这个就是要传达的命令的抽象类
};

class TaskRunner
{
    static vector<Task*> tasks; //这个是要执行的命令集合
    TaskRunner() {} //把构造函数放到私有成员,作为单件类
    TaskRunner& operator=(TaskRunner&);
    TaskRunner(const TaskRunner&);
    static TaskRunner tr;   //创建一个静态的执行对象
public:
    static void add(Task& t) { tasks.push_back(&t); }   //添加一条命令
    static void run()   //命令的执行
    {
        vector<Task*>::iterator it=tasks.begin();    //迭代器,遍历所有命令
        while(it != tasks.end())
            (*it++)->operation();   //执行命令
    }
};

TaskRunner TaskRunner::tr;
vector<Task*> TaskRunner::tasks;

class EvenSimulator
{
    clock_t creation;       //这个是表示事件创建时间
    clock_t delay;      //一段时间的延迟
public:
    EvenSimulator() : creation(clock())
    {
        delay=CLOCKS_PER_SEC/4*(rand()%20+1);    //得到随机产生的一个要延迟的时间
        cout<<"delay="<<delay<<endl;
    }
    bool fired()
    {
        return clock()>creation+delay;  //是否开火!!!!
    }
};

class Button
{
    bool pressed;   //按钮是否被按下
    string id;
    EvenSimulator e;        //类的组合
public:
    Button(string name) : pressed(false), id(name) {}   //初始化这个按钮
    void press() { pressed=true; }  //判断是否已经按下
    bool isPressed()
    {
        if(e.fired())
            press();
        return pressed; //返回看看是否已经按下了
    }
    friend ostream& operator<<(ostream& os, const Button& b)
    {
        return os<<b.id;    //输出这个按钮的ID
    }
};

class CheckButton : public Task
{
    Button& button; //类的组合
    bool handled;
public:
    CheckButton(Button& b) : button(b), handled(false) {}   //构造函数,这个是命令类
    void operation()
    {
        if(button.isPressed() && !handled)
        {
            cout<<button<<"pressed"<<endl;
            handled=true;   //标记按钮已经按下
        }
    }
};

void procedure1()
{
    TaskRunner::run();
}

void procedure2()
{
    TaskRunner::run();
}

void procedure3()
{
    TaskRunner::run();
}

int main()
{
    srand(time(0));
    Button b1("Button1"), b2("Button2"), b3("Button3");
    CheckButton cb1(b1), cb2(b2), cb3(b3);
    TaskRunner::add(cb1);   //添加一个按钮
    TaskRunner::add(cb2);
    TaskRunner::add(cb3);
    cout<<"Control-C to exit"<<endl;
    while(true) //不停地检测按钮的开启和关闭
    {
        procedure1();
        procedure2();
        procedure3();
    }

    return 0;
}


 

 

10.8 模板方法模式

作用:定义一个操作中的算法的骨架。而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

 

 

AbstractClass是抽象类,其实也就是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶层逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到之类实现。顶层逻辑也有可能调用一些具体方法。

ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass 与之对应,而每一ConcreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

 

1、public:public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用

     2、private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用,私有财产神圣不可侵犯嘛,即便是子女,朋友,都不可以使用。

     3、protected:protected对于子女、朋友来说,就是public的,可以自由使用,没有任何限制,而对于其他的外部class,protected就变成private。

         作用域       当前类    同一package   子孙类     其他package

           public        √         √             √           √

          protected     √         √             √           ×

          friendly      √         √             ×           ×

          private       √         ×             ×           ×

 

 

在没有继承的情况下,protected跟private相同。在派生类的时候才出现分化。

上面那段英文前两条都很好理解,基类对象不能访问基类的protected成员,派生类中可以访问基类的protected成员。也就是说private成员是不能被继承的,只有public,protected的成员才可以被继承。

 

 

TemplateMethod.cpp

 

/**
* 书本:【ThinkingInC++】
* 功能:设计模式之模板方法模式
* 文件:TemplateMethod.cpp
* 时间:2014年10月29日17:56:32
* 作者:cutter_point
*/

#include <iostream>

using namespace std;

class ApplicationFramework  //抽象类
{
protected:  //保护类型,类里面相当于private但是继承后相当于继承后子类里面的protected
    virtual void customize1()=0;    //纯虚函数
    virtual void customize2()=0;    //同上
public:
    void templateMethod()
    {
        for(int i=0 ; i < 5 ; ++i)
        {
            customize1();
            customize2();
        }
    }
};

//好的这里创建一个新的类,继承上面的类
class MyApp : public ApplicationFramework
{
protected:
    void customize1() { cout<<"Hello "<<endl; }
    void customize2() { cout<<"World! "<<endl; }
};

//或者可以用其他的
class MyApp2 : public ApplicationFramework
{
protected:
    void customize1() { cout<<"Hello "; }
    void customize2() { cout<<"cutter_point! "<<endl; }
};

//主函数
int main()
{
    MyApp app;
    MyApp2 app2;
    app.templateMethod();
    cout<<"-----------------------------"<<endl;
    app2.templateMethod();

    return 0;
}



 

 

 

 

10.9 策略模式:运行时选择算法

 

组合优于继承

 

在程序运行时,可以插入变化的代码。

 

 

用CS里的人物作为例子,每个人都可以有几个武器,武器之间动态切换,武器拥有统一的攻击命令:

 

http://blog.csdn.net/lcl_data/article/details/10255125

 

什么是策略模式

策略模式属于对象行为模式,其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使它们可以相互替换。

 

策略模式的优缺点

优点:

(1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
(2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。


缺点:

(1)       客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。

 

http://www.2cto.com/kf/201306/221984.html

 

应用场景:
  1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。(例如FlyBehavior和QuackBehavior)
  2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。(例如FlyBehavior和QuackBehavior的具体实现可任意变化或扩充)
  3、 对客户(Duck)隐藏具体策略(算法)的实现细节,彼此完全独立。

 

WeaponBehavior.cpp

 

/**
* 书本:【ThinkingInC++】
* 功能:CS里的人物作为例子,每个人都可以有几个武器,武器之间动态切换,
*      武器拥有统一的攻击命令:
* 文件:WeaponBehavior.cpp
* 时间:2014年10月29日17:57:05
* 作者:cutter_point
*/

#include <iostream>

using namespace std;

class Change    //任务切换武器
{
public:
    virtual void use()=0;   //使用武器的动作
};

class AK47 : public Change
{
public:
    void use()
    {
        cout<<"怒吼的AK47!!"<<endl;
    }
};

class M16A1 : public Change
{
public:
    void use()
    {
        cout<<"怒吼的M16A1!!"<<endl;
    }
};

//上面两个是两个策略
//接下来我们设计一个代理类,来控制对特定的策略对象的选择和使用
class Context   //这里用类的组合
{
    Change* change;  //使用引用,避免充分使用内存
public:
    Context() : change(0) {}
    void setChange(Change* c)
    {
        this->change=c;
    }
    void fight()
    {
        if ( this->change == NULL)
        {
            cout << "没有武器,等死吧!" << endl;
        }
        else
        {
            change->use();
        }
    }
};

int main()
{
    //两个策略
    Change* ak47=new AK47();
    Change* m16a1=new M16A1();

    //代理类
    Context* ct=new Context();

    ct->fight();
    cout<<endl;

    ct->setChange(ak47);
    ct->fight();
    cout << endl;

    ct->setChange(m16a1);
    ct->fight();

    return 0;
}


 

 

 

 

10.13 观测者模式

 

10.13.1 “内部类”方法

 

C++内部类访问外部类的一个方法:

 

 #include <iostream>
 #define METHOD_PROLOGUE(theClass, localClass)       theClass* pThis = ((theClass*)((char*)(this) -       offsetof(theClass, m_x##localClass)));   
  using namespace std;
  
  class Outer
  {
 public:
     Outer(){m_outerInt=0;}
 private:
     int m_outerInt;
 public:
     //内部类定义开始
     class Inner
     {
     public:
         Inner(){m_innerInt=1;}
     private:
         int m_innerInt;
     public:
         void DisplayIn(){cout<<m_innerInt<<endl;}
         // 在此函数中访问外部类实例数据
         void setOut()
         {
             METHOD_PROLOGUE(Outer,Inner);
             pThis->m_outerInt=10;
         }
     } m_xInner;
     //End内部类
 public:
     void DisplayOut(){cout<<m_outerInt<<endl;}
 };
 
 int main()
 {
     Outer out;
     out.DisplayOut();
     out.m_xInner.setOut();
     out.DisplayOut();
     return 0;
 }


 

http://www.cnblogs.com/qzhforthelife/archive/2013/07/31/3226885.html

 

这里面使用了

offsetof宏解析

offsetof(s,m),这是一个宏,MSDN文档的说明如下:

Retrieves the offset of a member from thebeginning of its parent structure.

size_t offsetof(
structName,
memberName
);

 

offsetof returns the offset in bytes of thespecified member from the beginning of its parent data structure. It isundefined for bit fields.

 

offsetoff(struct_t,member)宏的作用就是获得成员member在类型struct_t中的偏移量。

 

http://www.cppblog.com/lovedday/archive/2007/09/24/32801.html

 

 

关于括号运算符的重载

 

1.	#include <iostream>  
2.	using namespace std;  
3.	class Clastype  
4.	{  
5.	    public:  
6.	        Clastype(int a)  
7.	        {  
8.	            cout << "Hello Clastype!" << a << endl;  
9.	        }  
10.	        bool operator ()(int b)  
11.	        {  
12.	            cout << "Hello Clastype()!" << b << endl;  
13.	            return true;  
14.	        }  
15.	};  
16.	int main()  
17.	{  
18.	    Clastype a(1);  
19.	    Clastype(2);  
20.	    Clastype t = Clastype(3);  
21.	    t(4);  
22.	    Clastype *b = new Clastype(5);  
23.	    (*b)(6);  
24.	}  

 

运行结果如下:

 

  1. @-desktop:~/test$ g++ -o o 6.cpp  
  2. @-desktop:~/test$ ./o  
  3. Hello Clastype!1  
  4. Hello Clastype!2  
  5. Hello Clastype!3  
  6. Hello Clastype()!4  
  7. Hello Clastype!5  
  8. Hello Clastype()!6  

 

 

http://blog.csdn.net/neonlight/article/details/6065196

InnerClassIdiom.cpp

 

/**
* 书本:【ThinkingInC++】
* 功能:向上类型转换成为多个不同的类型
* 文件:InnerClassIdiom.cpp
* 时间:2014年10月29日17:59:23
* 作者:cutter_point
*/

#include <iostream>
#include <string>

using namespace std;

class Poingable //抽象类
{
public:
    virtual void poing()=0;     //纯虚函数
};

//这里又一个函数使用了这个类,这个类是等会要用来向上转换的目标
void callPoing(Poingable& p)
{
    p.poing();
}

class Bingable
{
public:
    virtual void bing()=0;     //纯虚函数
};

//这里又一个函数使用了这个类,这个类是等会要用来向上转换的目标
void callBing(Bingable& b)
{
    b.bing();
}

//好开始定义这个内部类
class Outer
{
    string name;
    //定义第一个内部类
    class Inner1;   //声明
    friend class Outer::Inner1; //声明为友元,使他可以访问外部类,Java就不用这样直接就可以访问外部
    class Inner1 : public Poingable
    {
        Outer* parent;  //这是一个组合
    public:
        Inner1(Outer* p) : parent(p) {} //初始化,用Outer来初始化Inner1
        void poing()    //重新定义这个函数
        {
            cout<<"内部类调用poing的是:"<<parent->name<<endl;
        }
    }inner1;    //这里定义一个对象,和C中的struct类似

    //第二个inner类
    class Inner2;
    friend class Outer::Inner2;
    class Inner2 : public Bingable
    {
        Outer* parent;
    public:
        Inner2(Outer* p) : parent(p) {} //初始化,用Outer来初始化Inner1
        void bing()  //重新定义这个函数
        {
           cout<<"内部类调用bing的是:"<<parent->name<<endl;
        }
    }inner2;
public:
    Outer(const string& nm) : name(nm), inner1(this), inner2(this) {}
    //自动类型转换函数
    operator Poingable& () { cout<<"!!!"<<endl; return inner1; }
    operator Bingable& () { cout<<"= ="<<endl; return inner2; }

};

int main()
{
    Outer x("Ping Pong");
    cout<<"-----------"<<endl;
    callPoing(x);   //调用自动类型转换函数operator Poingable& () { cout<<"!!!"<<endl; return inner1; }
    callBing(x);    //调用自动类型转换函数operator Bingable& () { cout<<"= ="<<endl; return inner2; }

    return 0;
}


 

自动类型转换函数

C++提供类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个Complex类,可以在Complex类中这样定义类型转换函数:
    operator double( )
    {
        return real;
    }
函数返回double型变量real的值。它的作用是将一个Complex类对象转换为一个double型数据,其值是Complex类中的数据成员 real的值。请注意,函数名是operator double,这点是和运算符重载时的规律一致的(在定义运算符“+”的重载函数时,函数名是operator +)。

 

 

类型转换函数的一般形式为:
    operator 类型名( )
    {
        实现转换的语句
    }

 

http://see.xidian.edu.cn/cpp/biancheng/view/222.html

 

10.13.2 观测者模式举例

 

Observable  这个类是跟踪那些当一个类对象发生变化时需要被通知的对象

Argument   这个类是用于传递需要的任何参数类型

 

关于virtual析构函数

如果析构函数不用virtual,则
Base *p = new Derive();
delete p;
这里delete p删除的就是Derive类中的Base成份了,而对于Derive成员则无法删除,所以为了正确删除,则必须用virtual析构函数,具体请参考effective c++ 3td

 

 

 

关于"析构函数前加virtual"这个问题,综合大家的指点和书上的话,我想如果我理解的没有什么错误的话,它是这样子的:

  首先,每个派生类对象都有一个指向虚函数表的指针,访问任何虚函数都是间接通过这个指针进行的,之所以要用虚函数表,是因为调用一个虚函数的哪个版本是在运行过程(调用时指针所指的对象)才能确定的(动态绑定)。
  相对于虚函数,实函数的调用机制就简单的多:由于每个实函数只有一个版本,因此调用地址在编译时即可确定(静态绑定)

  析构函数也可以通过virtual修饰而声名为虚函数,虚析构函数与一般虚函数的不同之处在于:
  1》它的重定义函数就是派生类的析构函数,但不要求同名。
  2》一个虚析构函数的版本被调用后,接着就要调用执行基类版本,依次类推,直到调用执行了派生序列的最开始的那个虚析构函数版本为止。

 

http://bbs.csdn.net/topics/100009115

Observer.h

 

/**
* 书本:【ThinkingInC++】
* 功能:观察者的接口
* 文件:Observer.h
* 时间:2014年10月29日17:59:53
* 作者:cutter_point
*/
#ifndef OBSERVER_H_INCLUDED
#define OBSERVER_H_INCLUDED

class Observable;   //类的声明,这个类是跟踪那些当一个类对象发生变化时需要被通知的对象
class Argument {};  //这个类是用于传递需要的任何参数类型

class Observer
{
public:
    virtual void update(Observable* o, Argument* arg)=0;    //更新数据,把arg传到里面去
    virtual ~Observer() {}  //virtual的析构函数
};

#endif // OBSERVER_H_INCLUDED


 

 

Observable.h

 

/**
* 书本:【ThinkingInC++】
* 功能:这个类是跟踪那些当一个类对象发生变化时需要被通知的对象
* 文件:Observable.h
* 时间:2014年10月29日18:00:19
* 作者:cutter_point
*/
#ifndef OBSERVABLE_H_INCLUDED
#define OBSERVABLE_H_INCLUDED

#include <set>  //存放一堆观察者对象
#include "Observer.h"   //被观察的对象认为到了更新其所有观察者的时机时,调用这个函数

class Observable
{
    bool changed;   //判断数据是否发生改变的一个变量
    std::set<Observer*> observers;  //被观察者对象
protected:
    //两个功能型的函数
    virtual void setChanged() { changed=true; }
    virtual void clearChanged() { changed=false; }
public:
    virtual void addObserver(Observer& o)
    {
        observers.insert(&o);   //添加一个对象
    }
    virtual void deleteObserver(Observer& o)
    {
        observers.erase(&o);
    }
    virtual void deleteObservers()
    {
        observers.clear();
    }
    virtual int countObservers()
    {
        return observers.size();
    }
    virtual bool hasChange() { return changed; }

    //如果这个对象发生改变,更新其他的所有被观察者对象
    virtual void notifyObservers(Argument* arg=0)   //默认为0
    {
        if(!hasChange()) return;    //没有改变
        clearChanged();     //如果改变了,那么更新所有,并且把changed改为false
        std::set<Observer*>::iterator it;   //一个迭代器
        for(it=observers.begin() ; it != observers.end() ; ++it)
            (*it)->update(this, arg);   //每个对象全部都跟着改变
    }
    virtual ~Observable() {}

};

#endif // OBSERVABLE_H_INCLUDED


 

ObservedFlower.cpp

 

/**
* 书本:【ThinkingInC++】
* 功能:观察者模式,内部类的实现
* 文件:ObservedFlower.cpp
* 时间:2014年10月29日18:01:04
* 作者:cutter_point
*/

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include "Observable.h"

using namespace std;

class Flower
{
    bool isOpen;    //花开了么?
public:
    Flower() : isOpen(false), openNotifier(this), closeNotifier(this) {}
    void open() //花儿开启
    {
        isOpen=true;    //首先自己要知道花开了
        //然后通知其他的观察者,做出相应的动作
        //第一个内部类是观察话是否开了
        openNotifier.notifyObservers(); //全部更新数据
        closeNotifier.open();    //第二观察是否花谢,告诉他花没有谢,开了
    }

    void close()    //花儿谢了
    {
        isOpen=false;   //首先自己要知道花谢了
        closeNotifier.notifyObservers();    //第一个内部类是观察话是否开了
        openNotifier.close();   //第二观察是否花谢,告诉他花没有谢,开了
    }

    //开始定义内部类,当然你也可以定义为私有类型
    class OpenNotifier;
    friend class Flower::OpenNotifier;
    class OpenNotifier : public Observable
    {
        Flower* parent; //初始化的时候还是用的本类初始化
        bool alreadyOpen;   //准备就绪开启花朵
    public:
        OpenNotifier(Flower* f) : parent(f), alreadyOpen(false) {}
        void  notifyObservers(Argument* arg=0)  //更新数据
        {
            if(parent->isOpen && !alreadyOpen)
            {
                setChanged();
                Observable::notifyObservers();  //改变所有观察者绑定的对象
                alreadyOpen=true;
            }
        }
        void close() { alreadyOpen=false; } //如果花朵关闭了,通知他
    }openNotifier;

    //开始定义内部类,当然你也可以定义为私有类型
    class CloseNotifier;
    friend class Flower::CloseNotifier;
    class CloseNotifier : public Observable
    {
        Flower* parent; //初始化的时候还是用的本类初始化
        bool alreadyClosed;   //准备就绪凋谢花朵
    public:
        CloseNotifier(Flower* f) : parent(f), alreadyClosed(false) {}
        void  notifyObservers(Argument* arg=0)  //更新数据
        {
            if(!parent->isOpen && !alreadyClosed)
            {
                setChanged();
                Observable::notifyObservers();  //改变所有观察者绑定的对象
                alreadyClosed=true;
            }
        }
        void open() { alreadyClosed=false; } //如果花朵关闭了,通知他
    }closeNotifier;
};

//定义多种Observer
class Bee   //这是蜜蜂么。哈哈我English不太好
{
    string name;
    //好,内部类又开始了,我都要吐了
    class OpenObserver; //开启观察者
    friend class Bee::OpenObserver;
    class OpenObserver : public Observer
    {
        Bee* parent;    //放心,等会初始化的时候必定是本类,肥水不流外人田嘿嘿
    public:
        OpenObserver(Bee* b) : parent(b) {}
        void update(Observable*, Argument*)
        {
            cout<<"Bee名字:"<<parent->name<<"的早餐时间"<<endl;
        }
    }openObsrv;

    //好,内部类又开始了,我都要吐了
    class CloseObserver; //开启观察者
    friend class Bee::CloseObserver;
    class CloseObserver : public Observer
    {
        Bee* parent;    //放心,等会初始化的时候必定是本类,肥水不流外人田嘿嘿
    public:
        CloseObserver(Bee* b) : parent(b) {}
        void update(Observable*, Argument*)
        {
            cout<<"Bee名字:"<<parent->name<<"的嫖赌时间"<<endl;
        }
    }closeObsrv;
public:
    Bee(string nm) : name(nm), openObsrv(this), closeObsrv(this) {} //得,肥水不流外人田

    //两个函数函数
    Observer& openObserver() { return openObsrv; }
    Observer& closeObserver() { return closeObsrv; }
};

//不同的观察者
class Hummingbird   //这个估计是啄木鸟了,哈哈查了一下 蜂鸟
{
    string name;
    //好,内部类又开始了,我都要吐了
    class OpenObserver; //开启观察者
    friend class Hummingbird::OpenObserver;
    class OpenObserver : public Observer
    {
        Hummingbird* parent;    //放心,等会初始化的时候必定是本类,肥水不流外人田嘿嘿
    public:
        OpenObserver(Hummingbird* b) : parent(b) {}
        void update(Observable*, Argument*)
        {
            cout<<"Hummingbird名字:"<<parent->name<<"的早餐时间"<<endl;
        }
    }openObsrv;

    //好,内部类又开始了,我都要吐了
    class CloseObserver; //开启观察者
    friend class Hummingbird::CloseObserver;
    class CloseObserver : public Observer
    {
        Hummingbird* parent;    //放心,等会初始化的时候必定是本类,肥水不流外人田嘿嘿
    public:
        CloseObserver(Hummingbird* b) : parent(b) {}
        void update(Observable*, Argument*)
        {
            cout<<"Hummingbird名字:"<<parent->name<<"的嫖赌时间"<<endl;
        }
    }closeObsrv;
public:
    Hummingbird(string nm) : name(nm), openObsrv(this), closeObsrv(this) {} //得,肥水不流外人田

    //两个函数函数
    Observer& openObserver() { return openObsrv; }
    Observer& closeObserver() { return closeObsrv; }

};

int main()
{
    Flower f;   //给我来一朵花
    Bee ba("A"), bb("B");   //这是A,B啊,两只小蜜蜂啊,飞在花丛中啊
    Hummingbird ha("cutter"), hb("point");  //这个比A,B好看多了
    f.openNotifier.addObserver(ha.openObserver());
    f.openNotifier.addObserver(hb.openObserver());
    f.openNotifier.addObserver(ba.openObserver());
    f.openNotifier.addObserver(bb.openObserver());

    f.closeNotifier.addObserver(ha.closeObserver());
    f.closeNotifier.addObserver(hb.closeObserver());
    f.closeNotifier.addObserver(ba.closeObserver());
    f.closeNotifier.addObserver(bb.closeObserver());

    f.openNotifier.deleteObserver(hb.openObserver());

    f.open();
    f.open(); //没有改变,已经开启

    f.closeNotifier.deleteObserver(ba.closeObserver());

    f.close();
    f.close();  //没有改变,已经关闭

    f.openNotifier.deleteObservers();
    f.open();
    f.close();

    return 0;
}


 

更多观察者模式请可以参考:

 

http://blog.csdn.net/wuzhekai1985/article/details/6674984

 

http://blog.csdn.net/mafuli007/article/details/7239709

【ThinkingInC++】76、设计模式