观察者模式(Observer Pattern)是典型的行为型设计模式,MVC 架构就是其经典应用。它定义了一对多的依赖关系:当一个对象的状态发生改变时,所有依赖它的对象都会收到通知并自动更新。
适用场景
- 场景1:观看电视频道——观众主动订阅感兴趣的频道,频道有内容时通知订阅者。
- 场景2:消息订阅——订阅自己关心的状态,当该状态的消息到达时自动得到通知。
缺点
- 每次状态变更都需要广播,并逐一筛选合适的观察者,在观察者数量较多时开销较大。
例1:C++ 基础实现
头文件
#include "PublicHeaders.h"
#include <vector>
#include <string>
class Observer;
class Subject
{
public:
virtual void Attach(Observer*) = 0;
virtual void Detach(Observer*) = 0;
virtual void Notify() = 0;
void setState(const std::string&state)
{
this->_state = state;
}
const std::string& getState()const
{
return _state;
}
private:
std::string _state;
protected:
std::vector<Observer*> _observers;
};
class ConCreateSubject :public Subject
{
public:
virtual void Attach(Observer*) override;
virtual void Detach(Observer*)override;
virtual void Notify() override;
};
class Observer
{
public:
virtual void Update(const std::string &state) = 0;
};
class ConCreateObserverA :public Observer
{
public:
virtual void Update(const std::string& state)override
{
if (state == "A")
{
cout << __FUNCTION__ << endl;
}
}
};
class ConCreateObserverB :public Observer
{
public:
virtual void Update(const std::string& state)override
{
if (state == "B")
{
cout << __FUNCTION__ << endl;
}
}
};
void testObserver();
源文件
#include "Observer.h"
void ConCreateSubject::Attach(Observer*observer)
{
_observers.push_back(observer);
}
void ConCreateSubject::Detach(Observer*observer)
{
auto iter = std::find(_observers.begin(), _observers.end(), observer);
if (iter != _observers.end())
{
_observers.erase(iter);
}
}
void ConCreateSubject::Notify()
{
for (int i = 0; i < _observers.size(); ++i)
{
_observers[i]->Update(this->getState());
}
}
void testObserver()
{
ConCreateSubject *sub = new ConCreateSubject;
auto a1 = new ConCreateObserverA;
sub->Attach(a1);
auto a2 = new ConCreateObserverA;
sub->Attach(a2);
auto b1 = new ConCreateObserverB;
sub->Attach(b1);
sub->setState("A");
sub->Notify();
sub->Detach(a1);
sub->Notify();
}
例2:Unity C# 游戏中的观察者实例
以下是在游戏中实现的观察者中心(NotifyCenter)示例。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public delegate void HandlerNotifyCenter(System.Object arg);
[System.Serializable]
class Recver
{
public string name;
public GameObject recver;
public HandlerNotifyCenter handler;
public Recver()
{
}
public void InVoke(System.Object arg)
{
handler(arg);
}
}
public class NotifyCenter : MonoBehaviour
{
static public NotifyCenter ins;
List<Recver> recvers = new List<Recver>();
void Awake()
{
ins = this;
}
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void addRecver(GameObject recver, string name, HandlerNotifyCenter handler)
{
// gameObject.SendMessage(msg);
Recver x = new Recver();
x.name = name;
x.handler = handler;
x.recver = recver;
recvers.Add(x);
}
public void removeRecver(GameObject recver, string name)
{
foreach (Recver obj in recvers)
{
if (name == obj.name && recver == obj.recver)
{
recvers.Remove(obj);
}
}
}
public void sendMessage(string msg, System.Object arg)
{
foreach (Recver obj in recvers)
{
if (msg == obj.name)
{
obj.InVoke(arg);
}
}
}
}
添加观察者
NotifyCenter x = NotifyCenter.ins;
x.addRecver(gameObject, "addCoin", new HandlerNotifyCenter(addCoin));
public void addCoin(System.Object obj)
{
}
例3:C++ 基于 unordered_map 的简化实现
class NotifyCenter
{
public:
static NotifyCenter *ins;
static NotifyCenter*getInstance()
{
if (ins == nullptr)
{
ins = new NotifyCenter;
}
return ins;
}
void SendMessage(string name, void* data)
{
auto &func = _listeners[name];
if (func )
{
func(data);
}
}
void addListener(string name, std::function<void(void*data)> callback)
{
_listeners[name] = callback;
}
private:
std::unordered_map< string, std::function<void(void*data)> > _listeners;
};
NotifyCenter*NotifyCenter::ins = nullptr;
int main()
{
//添加接受者
NotifyCenter::getInstance()->addListener("john", [=](void *data)
{//回调
cout << (char*)data<<" call me " << endl;
});
//添加接受者
NotifyCenter::getInstance()->addListener("jack", [=](void *data)
{
//回调
cout << (char*)data << " call me " << endl;
});
//发送消息
NotifyCenter::getInstance()->SendMessage("john","hk");
//发送消息
NotifyCenter::getInstance()->SendMessage("john", "");
//发送消息
NotifyCenter::getInstance()->SendMessage("11", "");
system("pause");
return 0;
}
当然用 vector 也可以实现一对多的观察者通知。