C++设计模式二、观察者模式。

前言:观察者模式,顾名思义可定要有一个观察者(也叫订阅者),有观察者必要有被观察者,被观察者这里我们叫做主题。一个主题可以有多个订阅者,一个订阅者也可以由多个主题(不属于观察者的内容,不做研究),因为是一对多,所以类似广播通信。煮个栗子说明:报社和订报的人,报社就是主题,订报的人就是观察者,报社出了一期新的报纸,要通知订阅报纸的人,订报的人收到报纸,做出反应(读取还是扔掉)。

那么,问题来了,怎么实现一个对象(主题)做出变化,另一个对象(订阅者)收到消息并且做出改变呢?那么两者肯定有耦合关系。观察者模式是怎么实现的呢?在观察这模式中,主题类中添加一个观察者类的链表,通过成员函数通知观察者,观察者收到消息,做出反应。是不是还是感到一脸懵逼,没关系,往下看代码实现。

注意:此项设计模式设计到一项概念就是链表,没有list知识的,也不碍事,现学现卖亦可。代买中有详细解释,相信你能看懂。

obs.h代码如下:

#ifndef   _OBS_H
#define   _OBS_H
#include<string>
#include<list>
#include<iostream>
using namespace std;
class NEWS;//因Observe中有NEWS对象,所以要先声明。
class Observe//声明一个抽象观察者类;
{
public:
	string name;//定义观察者名单,声明为公用的是因为在主题NEWS中输出了观察者名单。
	NEWS* news;//定义了主题对象
public:
	Observe();//默认构造函数
	~Observe();//析构函数
	Observe(string n_name, NEWS*n_news):name(n_name), news(n_news)//见注1。
	{
	}
	virtual void update() = 0;//声明纯虚函数。见注2。
};
Observe::Observe() {}//默认构造函数
Observe::~Observe() {}//析构函数
class obsA :public Observe//定义具体观察者obsA
{
public:
	obsA();
	~obsA();
	obsA(string name, NEWS*news) :Observe(name, news)
	{

	}
	void update();//观察者obsA收到消息更新自己的动作。
};
class obsB :public Observe
{
public:
	obsB();
	~obsB();
	obsB(string name, NEWS*news) :Observe(name, news)
	{

	}
	void update();//观察者obsB收到消息更新自己的动作。
};
class obsC :public Observe
{
public:
	obsC();
	~obsC();
	obsC(string name, NEWS*news) :Observe(name, news)
	{

	}
	void update();//观察者obsC收到消息更新自己的动作。
};
class NEWS//定义抽象基类新闻类
{
protected:
	list<Observe*>Obs;//观察者模式的核心--在一个对象中存在另一个对象的链表
public:
	string act;
	virtual void add(Observe*) = 0;
	virtual void Delete(Observe*) = 0;
	virtual void notify() = 0;
	virtual void Show() = 0;
};
class newsA :public NEWS//抽象新闻类实例化
{
public:
	void add(Observe*obs)//添加订阅者
	{
		Obs.push_back(obs);
	}
	void Delete(Observe*obs)//删除订阅者
	{
		list<Observe*>::iterator it;
		for (it = Obs.begin(); it != Obs.end(); )//见注3。
		{
			if ((*it) == obs)
            {    
                it=Obs.erase(it);
            }
            else
            {
                it++;
            }
				
		}
	}
	void Show()
	{
		list<Observe*>::iterator it;
		cout << "当前订阅人员名单:" << endl;
		for (it = Obs.begin(); it != Obs.end(); it++)//注意begin和end后面的括号不要忘记了
		{
			cout <<(*it)->name << endl;//公有化观察者对象成员name。
		}
	}
	void notify()
	{
		list<Observe*>::iterator it;
		for (it = Obs.begin(); it != Obs.end(); it++)
		{
			(*it)->update();//观察者模式的另一个核心--通知所有观察者对象的函数
		}
	}

};
obsA::obsA(){}
obsA::~obsA() {}
void obsA::update()
{
	cout << name << " 收到消息:" << news->act << endl;
	cout << "我不想看,扔掉" << endl;
}
obsB::obsB() {}
obsB::~obsB() {}
void obsB::update()
{
	cout << name << " 收到消息:" << news->act << endl;
	cout << "放在桌子上,一会去看" << endl;

}
obsC::obsC() {}
obsC::~obsC() {}
void obsC::update()
{
	cout << name << " 收到消息:" << news->act << endl;
	cout << "不想看China Daily的报纸了,打电话告诉出版社取消订阅" << endl;

}
#endif

主程序实现如下:

#include "obs.h"
#include <stdlib.h>

int main()
{
	NEWS *ChinaDaily = new newsA();//见注4。
	Observe *xiaoming = new obsA("xiaoming", ChinaDaily);
	Observe *xiaowang = new obsB("xiaowang", ChinaDaily);
	Observe *xiaozhang = new obsC("xiaozhang", ChinaDaily);
	ChinaDaily->add(xiaoming);//添加订阅者名单
	ChinaDaily->add(xiaowang);
	ChinaDaily->add(xiaozhang);
	ChinaDaily->Show();//输出订阅者名单
	cout << endl;
	ChinaDaily->act = "ChinaDaily有新报纸派送啦";//报社做出反应
	ChinaDaily->notify();//通知订阅者
	cout << endl;
	ChinaDaily->Delete(xiaozhang);
	ChinaDaily->Show();
	cout << endl;
	return 0;
}

运行结果:

注1:

此乃列表成员初始化变量。还有一种成员初始化变量看起来很玄乎。

    Observe(string name, NEWS*news) 
    {
        this->name = name;
        this->news = news;
    }

第一次看见的时候,不知道你懵不懵,反正我懵了。this什么鬼?仔细一看,给变量赋值的时候,变量名字起的一样,如果不加this,直接写上name =name 我感觉会更懵。完全可以把变量名字换成另外一个,但是使用this看起来更加简洁,更加美观,做成了变量的统一,看个人喜好吧。

注2:

虚函数为零为纯虚函数,这是抽象类的标志。大家知道抽象基类不能实例化,但是为什么要定义抽象类呢?不定义抽象基类照样可以实现功能。查阅了资料,以下来自百度。

四个字:制定标准
纯虚函数是为你的程序制定一种标准,即只要你继承了我,就必须按照我和标准来,实现我所有的方法,否则你也是虚拟的,和JAVA里的接口一样,都是制定标准,为了使程序更加通用化,可重用性提高,让所有实现它或继承自它的子类全部按同一标准来工作,你想想大家都按标准来对程序的益处是什么?

注3:

删除list成员。或许你很奇怪为什么会这样写,并且for循环里面就两个参数。原因是当list遍历成员并且想要用erase删除的时候,erase迭代器之后,原来的迭代器就失效了,程序编译没有问题,但是执行的时候就会出现错误。erase会返回一个指向list下一个元素的iter,如果想要遍历就需要用返回的iter继续操作,如果不想遍历,直接加上一条break亦可。

注4:

这里是定义了一个指向子类对象的父类指针。这是面向对象编程的特性--多态。父类指针指向子类,则此指针只能访问父类的成员函数,但是这样就无法实现多态,我想要实现多态怎么办呢?只需要在成员函数前面加上virtual就可以了。

总结:观察者模式的核心就是,主题(被观察者)中有一个订阅者(观察者)链表,当主题发生变化的时候,执行主题中notify函数,循环链表,执行观察者中的update函数

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值