观察者模式

观察者模式

观察者模式又叫发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听同一个对象的状态变化,当这个被监听的对象状态发生变化 通知所有观察者,观察者更新自己的状态或者触发其他行为

在实际的开发中,通常有其他对象需要监听一个对象的状态变化,并作出响应的业务逻辑,而我们如果把这些对象(观察者)统一由被监听的对象管理, 不得不建立一种依赖关系,这就导致两种对象的耦合度变高,不容易扩展维护,观察者模式会使它们的耦合度降低,让它们都依赖与各自更高层的抽象。

例如在游戏中某个BOSS死亡状态、角色血量变化状态往往触发很多事件,例如通知场景、队友、其他怪物等等

从下面的UML图中我们可以发现每个观察者必须有相同的接口供被监听对象调用,这也是观察者模式的不足,其实每个观察者可以传入一个参数、返回类型相同的 函数指针

使用观察者模式在处理业务逻辑时还需要注意顺序问题,即当被监听者的状态发生变化后依次调用事件时,前后事件触发的逻辑是否有关联等等。

UML类图


Alt text

代码示例


#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;

class Observer;

class Entity
{
public:
	Entity()
	{
		m_nFlag = 0;
		m_vecObserver.clear();
	}
	virtual ~Entity()
	{

	}
	void Attach(Observer* pObserver)
	{
		if (nullptr == pObserver)
		{
			return;
		}
		m_vecObserver.push_back(pObserver);
	}
	void detach(Observer* pObserver)
	{
		if (nullptr == pObserver)
		{
			return;
		}
		for (std::vector<Observer*>::iterator it = m_vecObserver.begin();it!= m_vecObserver.end();)
		{
			if (*it == pObserver)
			{
				m_vecObserver.erase(it);
				break;
			}
			else
			{
				++it;
			}
		}
	}

	void Notify();

protected:
	int m_nFlag;

private:
	std::vector<Observer*> m_vecObserver;
};

class Monster : public Entity
{
public:
	Monster()
	{
	}
	~Monster()
	{
	}
	void SetDeadFlag()
	{
		if (IsDead())
		{
			return;
		}
		m_nFlag |= 1;
		Notify();
	}
	bool IsDead()
	{
		// 假设第一位为死亡标记
		return m_nFlag & 1;
	}
};

class Observer
{
public:
	virtual ~Observer()
	{
	}
	virtual void Update()
	{
	}
};

class DeadObserver : public Observer
{
public:
	DeadObserver(Entity* pEntity)
	{
		m_pEntity = pEntity;
	}
	virtual void Update()
	{
		cout << "DeadObserver::Update" << endl;
	}
private:
	Entity *m_pEntity;
};

void Entity::Notify()
{
	for (auto one : m_vecObserver)
	{
		one->Update();
	}
}

int main()
{
	{
		Monster objMonster;
		DeadObserver objDeadObserver(&objMonster);
		objMonster.Attach(&objDeadObserver);
		objMonster.SetDeadFlag();
	}
	system("pause");
	return 0;
}

输出:

DeadObserver::Update

调整后


#include "stdafx.h"
#include <iostream>
#include <vector>
#include <map>
#include <memory>
#include <functional>
using namespace std;

enum EntityEvent
{
	E_DEAD	 = 0,
	E_Revive = 1,
};

class Observer;

class Entity
{
public:
	Entity()
	{
		m_nFlag = 0;
		m_mapObserver.clear();
	}
	virtual ~Entity()
	{
	}
	void Attach(Observer* pObserver,EntityEvent eventType)
	{
		if (nullptr == pObserver)
		{
			return;
		}
		m_mapObserver[eventType] = pObserver;
	}
	void Detach(Observer* pObserver, EntityEvent eventType)
	{
		if (nullptr == pObserver)
		{
			return;
		}
		auto it = m_mapObserver.find(eventType);
		if (it == m_mapObserver.end())
		{
			return;
		}
		m_mapObserver.erase(it);
	}

	void Notify(EntityEvent eventType);

protected:
	int m_nFlag;
	std::map<EntityEvent, Observer*> m_mapObserver;
};

class Monster : public Entity
{
public:
	Monster()
	{
	}
	~Monster()
	{
	}
	void SetDeadFlag()
	{
		if (IsDead())
		{
			return;
		}
		m_nFlag |= 1;
		Notify(EntityEvent::E_DEAD);
	}
	bool IsDead()
	{
		// 假设第一位为死亡标记
		return m_nFlag & 1;
	}
};

class Observer
{
public:
	virtual ~Observer()
	{
	}
	virtual void Update(Entity* pEntity)
	{
		cout << "Observer::Update" << endl;
		for (auto one : m_vecFun)
		{
			one(pEntity);
		}
	}

	void RegistEvent(std::function<void(Entity*)> fun)
	{
		m_vecFun.push_back(fun);
	}

private:
	std::vector<std::function<void(Entity*)>> m_vecFun;
};

class DeadObserver : public Observer
{
public:
	DeadObserver()
	{
	}
	virtual void Update(Entity* pEntity)
	{
		cout << "DeadObserver::Update" << endl;
		Observer::Update(pEntity);
	}
};

void Entity::Notify(EntityEvent eventType)
{
	auto it = m_mapObserver.find(eventType);
	if (it == m_mapObserver.end())
	{
		return;
	}
	it->second->Update(this);
}

class Area
{
public:
	void DeadEntity(Entity* pEntiy)
	{
		cout << "Area::DeadEntity" << endl;
	}
};

class Role
{
public:
	void DeadMonster(Entity* pEntiy)
	{
		cout << "Role::DeadMonster" << endl;
	}
};

int main()
{
	{
		Monster objMonster;
		DeadObserver objDeadObserver;
		Area objArea;
		Role objRole;
		objDeadObserver.RegistEvent(std::bind(&Area::DeadEntity, &objArea,std::placeholders::_1));
		objDeadObserver.RegistEvent(std::bind(&Role::DeadMonster, &objRole, std::placeholders::_1));
		objMonster.Attach(&objDeadObserver, EntityEvent::E_DEAD);
		objMonster.SetDeadFlag();
	}
	system("pause");
	return 0;
}

输出:

DeadObserver::Update
Observer::Update
Area::DeadEntity
Role::DeadMonster