当前位置:网站首页>05 observer mode

05 observer mode

2022-06-27 07:49:00 zzyzxb

One : An example of inefficiency caused by traversal problems

#ifdef _DEBUG  // Only in Debug( debugging ) In mode 
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__)  // Redefinition new Operator 
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace nmsp1
{
	class Fighter;  // Class forward declaration 
	list<Fighter*> g_playerList;

	// Player parent class ( Former combatants )
	class Fighter
	{
	public:
		Fighter(int tmpID, string tmpName) :m_iPlayerID(tmpID), m_sPlayerName(tmpName)  // Constructors 
		{
			m_iFamilyID = -1;  //-1 It means that you have not joined any family 
		}
		virtual ~Fighter() {}  // Destructor 

	public:
		void SetFamilyID(int tmpID)  // When you join a family, you should set up a family ID
		{
			m_iFamilyID = tmpID;
		}

	public:
		void SayWords(string tmpContent)  // The player said something 
		{
			if (m_iFamilyID != -1)
			{
				// The player belongs to a family , The chat content information should be transmitted to other players in the family 
				for (auto iter = g_playerList.begin(); iter != g_playerList.end(); ++iter)
				{
					if (m_iFamilyID == (*iter)->m_iFamilyID)
					{
						// Other players in the same family should also receive chat messages 
						NotifyWords((*iter), tmpContent);
					}
				}
			}
		}

	private:
		void NotifyWords(Fighter* otherPlayer, string tmpContent)  // Other players have received chat messages from the current player 
		{
			// display information 
			cout << " The player :" << otherPlayer->m_sPlayerName << " Received player :" << m_sPlayerName << "  Chat messages sent :" << tmpContent << endl;
		}

	private:
		int m_iPlayerID;  // The player ID, Globally unique 
		string m_sPlayerName;  // Player name 
		int m_iFamilyID;  // family ID
	};

	//" warrior " Class player , The parent class is Fighter
	class F_Warrior :public Fighter
	{
	public:
		F_Warrior(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {}  // Constructors 
	};

	//" Master " Class player , The parent class is Fighter
	class F_Mage :public Fighter
	{
	public:
		F_Mage(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {}  // Constructors 
	};
}

int main()
{
	// Create gamers 
	nmsp1::Fighter* pplayerobj1 = new nmsp1::F_Warrior(10, " Zhang San ");  // In the actual game, a lot of data is taken from the database 
	pplayerobj1->SetFamilyID(100);  // Suppose the player's family ID yes 100
	nmsp1::g_playerList.push_back(pplayerobj1);  // Add to the global player list 

	nmsp1::Fighter* pplayerobj2 = new nmsp1::F_Warrior(20, " Li Si ");
	pplayerobj2->SetFamilyID(100);
	nmsp1::g_playerList.push_back(pplayerobj2);

	nmsp1::Fighter* pplayerobj3 = new nmsp1::F_Mage(30, " Wang Wu ");
	pplayerobj3->SetFamilyID(100);
	nmsp1::g_playerList.push_back(pplayerobj3);

	nmsp1::Fighter* pplayerobj4 = new nmsp1::F_Mage(50, " Zhao Liu ");
	pplayerobj4->SetFamilyID(200);  // Zhao Liu and the first three belong to two different families 
	nmsp1::g_playerList.push_back(pplayerobj4);

	// When a player chats , People of the same race should receive this message 
	pplayerobj1->SayWords(" The whole clan immediately gathered in the swamp , Prepare to attack !");

	// Release resources 
	delete pplayerobj1;
	delete pplayerobj2;
	delete pplayerobj3;
	delete pplayerobj4;

	std::cout << " Main thread execution completed \n";
}

Two : Bring in the observer (Observer) Pattern

The code for using the observer design pattern is as follows

#ifdef _DEBUG  // Only in Debug( debugging ) In mode 
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__)  // Redefinition new Operator 
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace nmsp1
{
	class Fighter;  // Class forward declaration 
	list<Fighter*> g_playerList;

	// Player parent class ( Former combatants )
	class Fighter
	{
	public:
		Fighter(int tmpID, string tmpName) :m_iPlayerID(tmpID), m_sPlayerName(tmpName)  // Constructors 
		{
			m_iFamilyID = -1;  //-1 It means that you have not joined any family 
		}
		virtual ~Fighter() {}  // Destructor 

	public:
		void SetFamilyID(int tmpID)  // When you join a family, you should set up a family ID
		{
			m_iFamilyID = tmpID;
		}

	public:
		void SayWords(string tmpContent)  // The player said something 
		{
			if (m_iFamilyID != -1)
			{
				// The player belongs to a family , The chat content information should be transmitted to other players in the family 
				for (auto iter = g_playerList.begin(); iter != g_playerList.end(); ++iter)
				{
					if (m_iFamilyID == (*iter)->m_iFamilyID)
					{
						// Other players in the same family should also receive chat messages 
						NotifyWords((*iter), tmpContent);
					}
				}
			}
		}

	private:
		void NotifyWords(Fighter* otherPlayer, string tmpContent)  // Other players have received chat messages from the current player 
		{
			// display information 
			cout << " The player :" << otherPlayer->m_sPlayerName << " Received player :" << m_sPlayerName << "  Chat messages sent :" << tmpContent << endl;
		}

	private:
		int m_iPlayerID;  // The player ID, Globally unique 
		string m_sPlayerName;  // Player name 
		int m_iFamilyID;  // family ID
	};

	//" warrior " Class player , The parent class is Fighter
	class F_Warrior :public Fighter
	{
	public:
		F_Warrior(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {}  // Constructors 
	};

	//" Master " Class player , The parent class is Fighter
	class F_Mage :public Fighter
	{
	public:
		F_Mage(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {}  // Constructors 
	};
}

namespace nmsp2
{
	class Fighter;  // Class forward declaration 
	class Notifier  // Notifier parent class 
	{
	public:
		virtual void addToList(Fighter* player) = 0;  // Add the players to be notified to the list 
		virtual void removeFromList(Fighter* player) = 0;  // Remove players from the list who do not want to be notified 
		virtual void notify(Fighter* talker, string tmpContent) = 0;  // Some details of the notice 
		virtual ~Notifier() {}
	};

	// Player parent class 
	class Fighter
	{
	public:
		Fighter(int tmpID, string tmpName) :m_iPlayerID(tmpID), m_sPlayerName(tmpName)  // Constructors 
		{
			m_iFamilyID = -1;  //-1 It means that you have not joined any family 
		}
		virtual ~Fighter() {}  // Destructor 

	public:
		void SetFamilyID(int tmpID)  // When you join a family, you should set up a family ID
		{
			m_iFamilyID = tmpID;
		}
		int GetFamilyID()  // Get the family ID
		{
			return m_iFamilyID;
		}

	public:
		void SayWords(string tmpContent, Notifier* notifier)  // The player said something 
		{
			notifier->notify(this, tmpContent);
		}
		// Notify the player to receive the chat message sent by other players , Virtual functions , Subclasses can be overridden to implement different functions 
		virtual void NotifyWords(Fighter* talker, string tmpContent)
		{
			// display information 
			cout << " The player :" << m_sPlayerName << " Received player :" << talker->m_sPlayerName << "  Chat messages sent :" << tmpContent << endl;
		}

	private:
		int m_iPlayerID;  // The player ID, Globally unique 
		string m_sPlayerName;  // Player name 
		int m_iFamilyID;  // family ID
	};

	//" warrior " Class player , The parent class is Fighter
	class F_Warrior :public Fighter
	{
	public:
		F_Warrior(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {}  // Constructors 
	};

	//" Master " Class player , The parent class is Fighter
	class F_Mage :public Fighter
	{
	public:
		F_Mage(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {}  // Constructors 
	};

	// Chat message notifier 
	class TalkNotifier :public Notifier
	{
	public:
		// Add players to the family list 
		virtual void addToList(Fighter* player)
		{
			int tmpfamilyid = player->GetFamilyID();
			if (tmpfamilyid != -1)  // Joined a family 
			{
				auto iter = m_familyList.find(tmpfamilyid);
				if (iter != m_familyList.end())
				{
					// The family id stay map There is already 
					iter->second.push_back(player);  // Directly add the player to the family 
				}
				else
				{
					// The family id stay map Does not exist in the 
					list<Fighter*> tmpplayerlist;
					m_familyList.insert(make_pair(tmpfamilyid, tmpplayerlist));  // With this family id by key, Add entries to map in 
					m_familyList[tmpfamilyid].push_back(player);  // Add the first player to the family 
				}
			}
		}
		// Remove players from the family list 
		virtual void removeFromList(Fighter* player)
		{
			int tmpfamilyid = player->GetFamilyID();
			if (tmpfamilyid != -1)  // Joined a family 
			{
				auto iter = m_familyList.find(tmpfamilyid);
				if (iter != m_familyList.end())
				{
					m_familyList[tmpfamilyid].remove(player);
				}
			}
		}
		// A player in the family said something , Call this function to notify everyone in the family 
		virtual void notify(Fighter* talker, string tmpContent)  //talker It's the talking player 
		{
			int tmpfamilyid = talker->GetFamilyID();
			if (tmpfamilyid != -1)  // Joined a family 
			{
				auto itermap = m_familyList.find(tmpfamilyid);
				if (itermap != m_familyList.end())
				{
					// Traverse all members of the family to which the player belongs 
					for (auto iterlist = itermap->second.begin(); iterlist != itermap->second.end(); ++iterlist)
					{
						(*iterlist)->NotifyWords(talker, tmpContent);
					}
				}
			}
		}

	private:
		//map Medium key Means family id,value Represents the list of all players in the family 
		map<int, list<Fighter*>> m_familyList;
	};
}

int main()
{
	// Create gamers 
	nmsp2::Fighter* pplayerobj1 = new nmsp2::F_Warrior(10, " Zhang San ");  // In the actual game, a lot of data is taken from the database .
	pplayerobj1->SetFamilyID(100);  // Suppose the family of the player's family ID yes 100

	nmsp2::Fighter* pplayerobj2 = new nmsp2::F_Warrior(20, " Li Si ");
	pplayerobj2->SetFamilyID(100);

	nmsp2::Fighter* pplayerobj3 = new nmsp2::F_Mage(30, " Wang Wu ");
	pplayerobj3->SetFamilyID(100);

	nmsp2::Fighter* pplayerobj4 = new nmsp2::F_Mage(50, " Zhao Liu ");
	pplayerobj4->SetFamilyID(200);  // Zhao Liu and the first three belong to two different families 

	// Create notifier 
	nmsp2::Notifier* ptalknotify = new nmsp2::TalkNotifier();

	// Players are added to the family list , Only in this way can we receive family chat messages 
	ptalknotify->addToList(pplayerobj1);
	ptalknotify->addToList(pplayerobj2);
	ptalknotify->addToList(pplayerobj3);
	ptalknotify->addToList(pplayerobj4);

	// A gamer chats , People of the same race should receive this message 
	pplayerobj1->SayWords(" The whole clan immediately gathered in the swamp , Prepare to attack !", ptalknotify);

	cout << " Wang Wu doesn't want to receive any more chat messages from other members of the family ---" << endl;
	ptalknotify->removeFromList(pplayerobj3);  // Remove Wang Wu from the family list 
	pplayerobj2->SayWords(" Please follow the instructions of the patriarch , Go to the swamp !", ptalknotify);

	// Release resources 
	delete pplayerobj1;
	delete pplayerobj2;
	delete pplayerobj3;
	delete pplayerobj4;
	delete ptalknotify;

	std::cout << " Main thread execution completed \n";
}

<1>pplayerobj1->SayWords(“ The whole clan immediately gathered in the swamp , Prepare to attack !”,ptalknotify);
<2>notifier->notify(this, tmpContent);
<3>int tmpfamilyid = talker->GetFamilyID();
<4>auto itermap = m_familyList.find(tmpfamilyid);
<5>for (auto iterlist = itermap->second.begin(); iterlist != itermap->second.end(); ++iterlist) // Traverse list Containers
(*iterlist)->NotifyWords(talker,tmpContent);
<6>cout << “ The player :” << m_sPlayerName << " Received player :" << talker->m_sPlayerName << " Chat messages sent :" << tmpContent << endl;

Observer design pattern definition ( Realize the intention ): Defines a one-to-many dependency between objects , When the state of an object changes , All objects that depend on it are automatically notified .

Release - subscribe (Publish-Subscribe)

 Observer mode UML chart
Observer mode UML chart

 Observer pattern without abstracting notifier UML chart
Observer pattern without abstracting notifier UML chart

The four roles of the observer model
a)Subject( The theme ): Observe the target , Here it means Notifier class .
b)ConcreteSubject( Specific themes ): Here it means TalkNotifier class .
c)Observer( The observer ): Here it means Fighter class .
d)ConcreteObserver( Concrete observer ): Here it means F_Warrior and F_Mage Subclass .

 Observer pattern role diagram
Observer pattern role diagram

The characteristics of the observer model
a) An abstract coupling is established between the observer and the observed object .
b) The observation target sends a notification to all observers in the observer list .
c) You can add new observers or observation targets by adding code , Comply with opening and closing principle .

3、 ... and : Apply Lenovo

a) Rescue the escort cart of family members .
b) Recommend the news to readers who like it .
c) By changing the graphics drawn by itself to truly reflect the company's sales data .
d) The turret will only be right 30 Players within meters ( Players in the list ) The attack .

原网站

版权声明
本文为[zzyzxb]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/178/202206270747264766.html