设计模式之观察者模式(ObserverPattern)
一.观察者模式(ObserverPattern)
在生活中会遇到很多使用观察者模式的案例,比如股票跌涨后,股民作为观察者会对股票进行交易;客人来敲门,门铃响了之后管家就会去开门等等。其中观察者与被观察者都有相互联系。
注: 接下来为了方便理解类之间的设计关系,采用StartUML画类图,用C++编程
二.编程实例
1.进制转换器
其中需要注意的有两个点:
1.Subject类与Observer类之间相互关联。
2.因为只要Subject模型一改变,所有的Observer派生类都要改变,所以Observer抽象类用static修饰Subject变量
3.一旦创建了新的Observer派生类,首先赋值Subject(被观察的类),然后将自己添加到Subject的通知对象中
类图设计
:
程序
:
#include <iostream>
#include <memory>
#include <vector>
#include <cstdio>
using namespace std;
/*
设计模式:观察者模式(Observer Pattern)
*/
/********************************观察者Observer***************************/
class Subject;
class Observer
{
public:
static Subject* _subject;//因为只要Subject一改变,所有的Observer派生类都要改变,所以用static修饰
public:
virtual ~Observer(){}
virtual void update() = 0;
};
Subject* Observer::_subject;
/********************************定义被观察的对象Subject***************************/
class Subject
{
vector<Observer*> _observers;
size_t _number;
public:
size_t getNumber()const
{
return _number;
}
void setNumber(size_t number)
{
_number = number;
notifyAllObservers();
}
void attachObserver(Observer* observer)
{
_observers.push_back(observer);
}
void notifyAllObservers()
{
for (auto& e: _observers)
e->update();
}
};
/********************************Observer派生类***************************/
//8进制
class OctObserver:public Observer
{
public:
OctObserver(Subject* subject)
{
_subject = subject;
_subject->attachObserver(this);//一旦创建了新的Observer派生类,首先赋值Subject(被观察的类),然后将自己添加到Subject的通知对象中
}
void update()
{
cout << "Oct:" << oct << _subject->getNumber() << endl;
}
};
//10进制
class DecObserver:public Observer
{
public:
DecObserver(Subject* subject)
{
_subject = subject;
_subject->attachObserver(this);
}
void update()
{
cout << "Dec:" << dec << _subject->getNumber() << endl;
}
};
//16进制
class HexObserver:public Observer
{
public:
HexObserver(Subject* subject)
{
_subject = subject;
_subject->attachObserver(this);
}
void update()
{
cout << "Hex:" << hex << _subject->getNumber() << endl;
}
};
int main()
{
unique_ptr<Subject> up(new Subject());
new DecObserver(up.get());
new HexObserver(up.get());
new OctObserver(up.get());
up->setNumber(10);
cout << "-----------------------" << endl;
up->setNumber(16);
return 0;
}
2.客人敲门案例
假设有客人,门铃,婴儿,护工四个类。
门铃是Subject被观察者,婴儿和护士是观察者。
婴儿和护工随时观察门铃,客人按动铃铛的时候,婴儿开始哭,护工去开门。
类图设计
:
程序
:
#include <iostream>
#include <memory>
#include <list>
#include <cstdio>
#include <algorithm>
using namespace std;
/*
观察者模式实际案例:
假设有客人,门铃,婴儿,护工四个类。
门铃是Subject被观察者,婴儿和护士是观察者。
婴儿和护工随时观察门铃,客人按动铃铛的时候,婴儿开始哭,护工去开门。
下面是案例设计的UML类图,完成程序:
*/
/***********************Observer AND Subject*****************************/
class Observer
{
public:
virtual string name() const = 0;
virtual void update() = 0;
};
class Subject
{
public:
virtual void attach(Observer *) = 0;
virtual void detach(Observer *) = 0;
virtual void notify() = 0;
};
/***********************Baby AND Nurse*****************************/
class Baby : public Observer
{
string _name;
public:
Baby(string name)
: _name(name)
{
}
string name() const { return _name; }
void update()
{
cout << _name << " is Crying" << endl;
}
};
class Nurse : public Observer
{
string _name;
public:
Nurse(string name)
: _name(name)
{
}
string name() const { return _name; }
void update()
{
cout << "Nurse is opening the door" << endl;
}
};
/***********************Ring*****************************/
class Ring : public Subject
{
list<Observer *> _oblist;
// list<Observer *> _goldenlist; //黄金会员
// list<Observer *> _diamondlist; //钻石会员
public:
void attach(Observer *ob)
{
auto it = find(_oblist.begin(), _oblist.end(), ob);
if (it == _oblist.end())
{
_oblist.push_back(ob);
}
}
void detach(Observer *ob)
{
auto it = find(_oblist.begin(), _oblist.end(), ob);
if (it != _oblist.end())
{
_oblist.erase(it);
}
}
void alarm()
{
notify();
}
void notify()
{
for (auto &e : _oblist)
e->update();
}
};
/***********************Ring*****************************/
class Guest
{
string _name;
public:
Guest(string name)
: _name(name)
{
}
string name() const { return _name; }
void knock(Ring* ring)
{
cout << _name << " is knocking the door" << endl;
ring->alarm();
}
};
int main()
{
unique_ptr<Observer> baby1(new Baby("haha"));
unique_ptr<Observer> baby2(new Baby("bala"));
unique_ptr<Observer> nurse(new Nurse("gj"));
unique_ptr<Ring> ring(new Ring());
ring->attach(baby1.get());
ring->attach(baby2.get());
ring->attach(nurse.get());
Guest guest("Uncle");
guest.knock(ring.get());
ring->detach(baby2.get());
guest.knock(ring.get());
return 0;
}