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,观察者自己决定是否要订阅,目标对此一无所知