觀察者模式
觀察者模式(Observer Pattern):定義對象間的一種一對多依賴關系,使得每當一個對象狀態發生改變時,其相關依賴對象皆得到通知並被自動更新。觀察者模式又叫做發布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
觀察者模式是一種對象行為型模式。UML類圖如下:
圖中有兩個基類:
- Observer(觀察者類)
- ConcretObserver
- Subject (目標類)
- ConcretSubject
Observer負責觀察Subject狀態的變化,Subject負責在自己狀態改變的時候通知觀察者類。下面放代碼:
- observer.h
#ifndef OBSERVER_H
#define OBSERVER_H
#include <QString>
#include "subject.h"
class Observer
{
public:
Observer(QString name);
virtual ~Observer();
virtual void Update(Subject* obj);
protected:
QString m_Name;
};
class ConcretObserver : public Observer
{
public:
ConcretObserver(QString name);
virtual ~ConcretObserver();
};
#endif // OBSERVER_H
- observer.cpp
#include "observer.h"
#include <QDebug>
Observer::Observer(QString name)
{
m_Name = name;
}
Observer::~Observer()
{
}
void Observer::Update(Subject* obj)
{
QString action;
if(m_Name == "李白")
action = "使用靈動的一技能快速避開";
else if(m_Name == "香香")
action = "使用翻滾,並走位找機會打出翻滾之后的加成傷害";
qDebug() << m_Name << " " << action;
}
ConcretObserver::ConcretObserver(QString name)
:Observer (name)
{
}
ConcretObserver::~ConcretObserver()
{
}
- subject.h
#ifndef SUBJECT_H
#define SUBJECT_H
#include <QVector>
class Observer;
class Subject
{
public:
Subject(QString name);
virtual ~Subject();
virtual void Attach(Observer* obs);
virtual void Detach(Observer* obs);
virtual void Notify();
virtual void SetAction(QString act);
virtual QString GetAction();
private:
QString m_Name;
QString m_Action;
QVector<Observer*> m_ObserverVec;
};
class ConcretSubject : public Subject
{
public:
ConcretSubject(QString name);
virtual ~ConcretSubject();
};
#endif // SUBJECT_H
- subject.cpp
#include "subject.h"
#include "observer.h"
Subject::Subject(QString name)
{
m_Name = name;
}
Subject::~Subject()
{
}
void Subject::Attach(Observer *obs)
{
m_ObserverVec.push_back(obs);
}
void Subject::Detach(Observer *obs)
{
QVector<Observer*>::iterator it;
for(it = m_ObserverVec.begin(); it != m_ObserverVec.end(); ++it)
{
if(*it == obs)
{
m_ObserverVec.erase(it);
}
}
}
void Subject::Notify()
{
for(Observer* obs : m_ObserverVec)
{
obs->Update(this);
}
}
void Subject::SetAction(QString act)
{
m_Action = act;
}
QString Subject::GetAction()
{
return m_Action;
}
ConcretSubject::ConcretSubject(QString name)
: Subject (name)
{
}
ConcretSubject::~ConcretSubject()
{
}
- main.cpp
#include <QCoreApplication>
#include "observer.h"
#include "subject.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Subject* sub = new ConcretSubject("敵方牛魔");
Observer* obj1 = new ConcretObserver("李白");
Observer* obj2 = new ConcretObserver("香香");
sub->Attach(obj1);
sub->Attach(obj2);
sub->SetAction("使用了大閃");
sub->Notify();
return a.exec();
}
牛魔使用了大閃,李白和想想分別用了自己的位移技能進行了躲避
作為一個喜歡在王者峽谷馳騁的男人在此模式中把峽谷世界和觀察者模式的設計動機機智的聯系起來方便讀者理解。其實游戲開發中的很多場景都是類似觀察者模式的,峽谷的每個人都會根據其他角色的狀態變化做出相應的動作,同時自己的動作也會通知到出自己之外的其他9個峽谷英雄,所以這些峽谷英雄其實是生活正在觀察者模式之中的男人和女人~
觀察者模式遵照了以下幾個設計原則:
- 依賴倒轉原則
- 開放封閉原則
參考《大話設計模式》和 https://design-patterns.readthedocs.io/zh_CN/latest/index.html