观察者模式又称发布-订阅模式,由观察者和目标组成,用法上跟Qt中的信号和槽倒是有那么几分相似。观察者模式中的观察者对应于Qt中的槽,目标则对应于Qt中的信号,而且也可以一个目标对应多个观察者。
现以杂志订阅为例,并以Magazine作为目标基类,以Person类作为观察者基类。Magazine有三个方法,订阅(subscribe),取消订阅(unsubscribe)和推送(push),并用一个vector存储订阅该杂志的用户。而Person作为接口类,有两个个方法——接收(accept),和获取名字(name)。
class Person
{
public:
virtual void accept(std::string magzineName) = 0;
std::string getName()
{
return name;
}
protected:
std::string name;
};
class Magazine
{
protected:
Magazine(){};
public:
//添加订阅用户
//就好比你跑到邮局去,跟工作人员说你要订阅某某杂志
//于是工作人员将你的名字记录下来
void subscribe(Person *p)
{
m_person.push_back(p);
}
void unsubscribe(Person *p) //删除取消订阅的用户
{
std::vector<Person*>::iterator it = m_person.end();
it = std::find(m_person.begin(), m_person.end(), p);
if(m_person.end() == it)
{
std::cout << p->getName() << " haven't subscribed yet." << std::endl;
return;
}
m_person.erase(it);
}
void push(std::string magzineName) //推送
{
for(int i = 0; i < m_person.size(); ++i)
{
m_person[i]->accept(magzineName);
}
}
private:
std::vector<Person*> m_person;
};
至此,观察者基类和目标基类就完成了。为了不弄得太复杂,现在假设我们只有一种杂志叫SATINE(瞎起的),和两个用户Lily和Tom。
class SATINE: public Magazine
{
public:
void newArrival() //SATINE上新了,推送给订阅用户
{
push("SATINE");
}
};
class Lily: public Person
{
public:
Lily()
{
name = "Lily";
}
void accept(std::string magazineName)
{
std::cout << getName() << " has accepted " << magazineName << std::endl;
}
};
class Tom: public Person
{
public:
Tom()
{
name = "Tom";
}
void accept(std::string magazineName)
{
std::cout << getName() << " has accepted " << magazineName << std::endl;
std::cout << getName() << " shared " << magazineName << " with his friend" <<
std::endl;
}
};
铺垫了这么久,该进入正题戏了,让我们一起嘿嘿嘿。
int main()
{
SATINE satine;
Lily lily;
Tom tom;
satine.subscribe(&lily);
satine.subscribe(&tom);
satine.newArrival();
return 0;
}