观察者模式.cpp
#include <iostream>
#include <list>
#include <map>
#include <memory>
using namespace std;
namespace ns1
{
class Fighter;
static list<shared_ptr<Fighter>> g_playerList;
class Fighter
{
int m_iPlayerID;
string m_sPlayerName;
int m_iFamilyID{-1};
private:
void ReceiveMessage(const Fighter *const otherPlayer, const string &tmpContent) const
{
cout << "receive message: " << tmpContent << ", from " << otherPlayer->m_sPlayerName << ", by " << m_sPlayerName << endl;
}
void NotifyWords(const shared_ptr<Fighter> &otherPlayer, const string &tmpContent) const
{
if (otherPlayer.get() != this)
otherPlayer->ReceiveMessage(this, tmpContent);
}
public:
Fighter(int tmpID, const string &tmpName) : m_iPlayerID(tmpID), m_sPlayerName(tmpName) {}
virtual ~Fighter() {}
public:
void SetFamilyID(int tmpID) { m_iFamilyID = tmpID; }
public:
void SayWords(const string &tmpContent) const
{
if (m_iFamilyID != -1)
for (auto iter = g_playerList.cbegin(); iter != g_playerList.cend(); ++iter)
if (m_iFamilyID == (*iter)->m_iFamilyID)
NotifyWords((*iter), tmpContent);
}
};
class F_Warrior : public Fighter
{
public:
F_Warrior(int tmpID, const string &tmpName) : Fighter(tmpID, tmpName) {}
};
class F_Mage : public Fighter
{
public:
F_Mage(int tmpID, const string &tmpName) : Fighter(tmpID, tmpName) {}
};
}
namespace ns2
{
class Fighter;
class Notifier
{
public:
virtual ~Notifier() {}
virtual void addToList(const shared_ptr<Fighter> &player) = 0;
virtual void removeFromList(const shared_ptr<Fighter> &player) = 0;
virtual void notify(const Fighter *const talker, const string &tmpContent) const = 0;
};
class Fighter
{
int m_iPlayerID;
string m_sPlayerName;
int m_iFamilyID{-1};
private:
void ReceiveMessage(const Fighter *const otherPlayer, const string &tmpContent) const
{
cout << "receive message: " << tmpContent << ", from " << otherPlayer->m_sPlayerName << ", by " << m_sPlayerName << endl;
}
public:
virtual ~Fighter() {}
Fighter(int tmpID, const string &tmpName) : m_iPlayerID(tmpID), m_sPlayerName(tmpName) {}
public:
void SetFamilyID(int tmpID) { m_iFamilyID = tmpID; }
int GetFamilyID() const { return m_iFamilyID; }
void SayWords(const string &tmpContent, const shared_ptr<Notifier> ¬ifier) const
{
notifier->notify(this, tmpContent);
}
public:
void NotifyWords(const Fighter *const talker, const string &tmpContent) const
{
if (talker != this)
ReceiveMessage(talker, tmpContent);
}
};
class F_Warrior : public Fighter
{
public:
F_Warrior(int tmpID, const string &tmpName) : Fighter(tmpID, tmpName) {}
};
class F_Mage : public Fighter
{
public:
F_Mage(int tmpID, const string &tmpName) : Fighter(tmpID, tmpName) {}
};
class TalkNotifier : public Notifier
{
map<int, list<shared_ptr<Fighter>>> m_familyList;
public:
void addToList(const shared_ptr<Fighter> &player) override
{
int tmpfamilyid = player->GetFamilyID();
if (tmpfamilyid != -1)
{
auto iter = m_familyList.find(tmpfamilyid);
if (iter != m_familyList.end())
{
iter->second.push_back(player);
}
else
{
list<shared_ptr<Fighter>> tmpplayerlist;
m_familyList.insert(make_pair(tmpfamilyid, tmpplayerlist));
m_familyList[tmpfamilyid].push_back(player);
}
}
}
void removeFromList(const shared_ptr<Fighter> &player) override
{
int tmpfamilyid = player->GetFamilyID();
if (tmpfamilyid != -1)
{
auto iter = m_familyList.find(tmpfamilyid);
if (iter != m_familyList.end())
{
m_familyList[tmpfamilyid].remove(player);
if (m_familyList[tmpfamilyid].empty())
m_familyList.erase(tmpfamilyid);
}
}
}
void notify(const Fighter *const talker, const string &tmpContent) const override
{
int tmpfamilyid = talker->GetFamilyID();
if (tmpfamilyid != -1)
{
auto itermap = m_familyList.find(tmpfamilyid);
if (itermap != m_familyList.end())
for (auto iterlist = itermap->second.cbegin(); iterlist != itermap->second.cend(); ++iterlist)
(*iterlist)->NotifyWords(talker, tmpContent);
}
}
};
}
int main()
{
#if 0
using namespace ns1;
shared_ptr<Fighter> pplayerobj1(new F_Warrior(10, "1"));
pplayerobj1->SetFamilyID(100);
g_playerList.push_back(pplayerobj1);
shared_ptr<Fighter> pplayerobj2(new F_Warrior(20, "2"));
pplayerobj2->SetFamilyID(100);
g_playerList.push_back(pplayerobj2);
shared_ptr<Fighter> pplayerobj3(new F_Mage(30, "3"));
pplayerobj3->SetFamilyID(100);
g_playerList.push_back(pplayerobj3);
shared_ptr<Fighter> pplayerobj4(new F_Mage(40, "4"));
pplayerobj4->SetFamilyID(200);
g_playerList.push_back(pplayerobj4);
pplayerobj1->SayWords("come on, attact!");
#endif
#if 1
using namespace ns2;
shared_ptr<Fighter> pplayerobj1(new F_Warrior(10, "1"));
pplayerobj1->SetFamilyID(100);
shared_ptr<Fighter> pplayerobj2(new F_Warrior(20, "2"));
pplayerobj2->SetFamilyID(100);
shared_ptr<Fighter> pplayerobj3(new F_Mage(30, "3"));
pplayerobj3->SetFamilyID(100);
shared_ptr<Fighter> pplayerobj4(new F_Mage(40, "4"));
pplayerobj4->SetFamilyID(200);
shared_ptr<Notifier> ptalknotify(new TalkNotifier());
ptalknotify->addToList(pplayerobj1);
ptalknotify->addToList(pplayerobj2);
ptalknotify->addToList(pplayerobj3);
ptalknotify->addToList(pplayerobj4);
pplayerobj1->SayWords("come on, attack!", ptalknotify);
cout << "leave---" << endl;
ptalknotify->removeFromList(pplayerobj3);
pplayerobj2->SayWords("listen, go together!", ptalknotify);
#endif
cout << "Over!\n";
return 0;
}