观察者模式学习

1,设计模式之观察者模式(c++)

Observer 模式要解决的问题为: 建立一个一( Subject)对多( Observer) 的依赖关系, 并且做到当“一” 变化的时候, 依赖这个“一”的多也能够同步改变。

使用动机:在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” -----一个(目标)对象的状态发生改变,所有依赖的(观察者)对象都将得到通知。如果这种依赖关系太过于紧密,将使软件不能很好地抵御变化。使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系,从而实现软件体系结构的松耦合。

在GOF的《设计模式:可复用面向对象软件的基础》一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也称为发布-订阅(publish-subscribe)。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者。

在这里插入图片描述

Subject(主题)
——目标知道它的观察者。可以有任意多个观察者观察同一个目标;
——提供注册和删除观察者对象的接口。

Observer(观察者)
——为那些在目标发生改变时需获得通知的对象定义一个更新接口。

ConcreteSubject(具体目标)
——将有关状态存入各ConcreteObserver对象;
——当它的状态发生改变时,向它的各个观察者发出通知。

ConcreteObserver(具体观察者)
——维护一个指向ConcreteSubject对象的引用;
——存储有关状态,这些状态应与目标的状态保持一致;
——实现Observer的更新接口以使自身状态与目标的状态保持一致。

2,代码示例

说明:该示例通过获取当前时间,模拟在周一 ~ 周日的时间通知,具现出两个观察者,进行注册,在收到具体周几时,所产生的不同行为,如有错误请指教。

//抽象主题类,

#include <list>
#include "ObServer.h"
#include <iostream>

using namespace std;

//抽象主题
class Object
{
public :
	Object();
	Object(int);
	virtual ~Object();
public:
	virtual void attach(ObServer* ob);
	virtual void detach(ObServer* ob);
	virtual void Notify();

	virtual void SetTmChange(int tm);
	virtual int GetTmChange();
protected:
	//list<ObServer*> _list;
	int _tmChange;
};

//抽象主题实现

#include "Object.h"

Object::Object(){}
Object::~Object()
{
	cout << "抽象主题析构" << endl;
}
void Object::attach(ObServer* ob){}
void Object::detach(ObServer* ob){}
void Object::Notify(){}
void Object::SetTmChange(int tm)
{
	_tmChange = tm;
}

int Object::GetTmChange()
{
	return _tmChange;
}

//抽象观察者

#include <string>
#include <QtWidgets/QMainWindow>

using namespace std;

class Object;
//抽象观察者
class ObServer 
{
protected:
    string name;
    Object *_object;
    string str;
public:
    ObServer();
    ObServer(Object* object,string name);
    virtual ~ObServer();
public:
    virtual void UpData() = 0;
    
};

//抽象观察者实现

#include "ObServer.h"
#include "Object.h"

ObServer::ObServer(){}
ObServer::ObServer(Object* object, string name)
{
    this->_object = object;
    this->name = name;
}

ObServer::~ObServer()
{
	if (_object != NULL)
	{
		delete _object;
		_object = NULL;
	}
}
void ObServer::UpData(){}

//具体主题类

#include "Object.h"

//具体主题类
class ConcreteObject:public Object
{
private:
	list<ObServer*> _list;
	//通过时间发生变化来进行测试
//	int _tmChange;
public:
	ConcreteObject();
	~ConcreteObject();
public:
	void attach(ObServer*);
	void detach(ObServer*);
	void Notify();
};

//具体主题实现

#include "ConcreteObject.h"

ConcreteObject::ConcreteObject(){}
ConcreteObject::~ConcreteObject(){}
void ConcreteObject::attach(ObServer*ob)
{
	_list.push_back(ob);
}

void ConcreteObject::detach(ObServer*ob)
{
	_list.remove(ob);
}

void ConcreteObject::Notify()
{
	for (list<ObServer *>::iterator it = _list.begin();it!= _list.end();it++)
	{
		(* it)->UpData();
	}
}

//具体观察者1

#include "ObServer.h" 
#include "Object.h"

class ConcreteObServer: public ObServer
{
	string _name;
//	Object* _object;
	string str;
public:
	ConcreteObServer();
	ConcreteObServer(string,Object *);
	~ConcreteObServer();
	
public :
	void UpData();
	string GetStr();

};

//观察者1实现
ConcreteObServer::ConcreteObServer(){}
ConcreteObServer::ConcreteObServer(string name, Object* object)
	:ObServer(object, name)
{
	_object = new Object(*object);
}

ConcreteObServer::~ConcreteObServer()
{
	if (_object != NULL)
	{
		delete _object;
		_object = NULL;
	}
}

void ConcreteObServer::UpData()
{
	switch (_object->GetTmChange())
	{
		case 0:
		{
			str = "周一";
			str += _name;
			str += "学习c++";
		}
		break;
		case 1:
		{
			str = "周二";
			str += _name;
			str += "学习java";
		}
		break;
		case 2:
		{
			str = "周三";
			str += _name;
			str += "学习python";
		}
		break;
		case 3:
		{
			str = "周四";
			str += _name;
			str += "学习设计模式";
		}
		break;
		case 4:
		{
			str = "周五";
			str += _name;
			str += "学习数据结构";
		}
		break;
		case 5:
		{
			str = "周六";
			str += _name;
			str += "锻炼身体";
		}
		break;
		case 6:
		{
			str = "周日";
			str += _name;
			str += "休息一天";
		}
		break;
	}
}

string ConcreteObServer::GetStr()
{
	return str;
}

//具体观察者2

#include "ObServer.h"
#include "Object.h"
class ConcreteObServer2 :
    public ObServer
{
public:
    string _name;
  //  Object* _object;
    string str;
public:
    ConcreteObServer2();
    ConcreteObServer2(string name,Object* object);
    ~ConcreteObServer2();
public:
    void UpData();
    string GetStr();
};

//具体观察者2实现
ConcreteObServer2::ConcreteObServer2(){}
ConcreteObServer2::ConcreteObServer2(string name, Object* object)
	:ObServer(object,name)
{
	_object = new Object(*object);
}

ConcreteObServer2::~ConcreteObServer2()
{
	if (_object != NULL)
	{
		delete _object;
		_object = NULL;
	}
}

void ConcreteObServer2::UpData()
{
	switch (_object->GetTmChange())
	{
	case 0:
		{
			str = "周一";
			str += _name;
			str += "打王者荣耀";
		}
		break;
		case 1:
		{
			str = "周二";
			str += _name;
			str += "打和平精英";
		}
		break;
		case 2:
		{
			str = "周三";
			str += _name;
			str += "打英雄联盟";
		}
		break;
		case 3:
		{
			str = "周四";
			str += _name;
			str += "打地下城与勇士";
		}
		break;
		case 4:
		{
			str = "周五";
			str += _name;
			str += "打cf";
		}
		break;
		case 5:
		{
			str = "周六";
			str += _name;
			str += "通宵打游戏";
		}
		break;
		case 6:
		{
			str = "周日";
			str += _name;
			str += "睡到17点起床";
		}
		break;
	}
}

string ConcreteObServer2::GetStr()
{
	return str;
}

//调用

QTest::QTest(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	_Conobject = new ConcreteObject();
	qtimer = new QTimer();
	qtimer->start(1000);
	connect(qtimer,&QTimer::timeout,this,&QTest::init);
}

void QTest::init()
{
	qtime = QTime::currentTime();
	int sec = qtime.second()%7;

	ConcreteObServer* _ConServer = new ConcreteObServer("小明", _Conobject);
	ConcreteObServer2* _ConServer2 = new ConcreteObServer2("小黑", _Conobject);

	_Conobject->attach(_ConServer);
	_Conobject->attach(_ConServer2);

	_Conobject->SetTmChange(sec);

	_Conobject->Notify();

	_Conobject->detach(_ConServer);
	_Conobject->detach(_ConServer2);

	ui.label->setText(QString::fromStdString(_ConServer->GetStr()));
	ui.label_2->setText(QString::fromStdString(_ConServer2->GetStr()));

	delete _ConServer;
	_ConServer = NULL;
	delete _ConServer2;
	_ConServer2 = NULL;
}

QTest::~QTest()
{
	delete qtimer;
	delete _Conobject;
}

要点总结:
1,通过抽象的接口,使得我们可以独立的改变目标与观察者,从而使两者之间的依赖达到松耦合(两者都依赖于抽象,核心要点就是抽象的通知依赖关系)。
2,目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播(向已订阅的观察者)。
3,观察者自己决定是否要订阅,目标对此一无所知

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值