Observer pattern design pattern

  In everyday life, traffic lights direct increasingly congested urban traffic. The red light is on, the car stops; the green light is on, the car continues to move; in this process, the traffic light is the car's observation target, and the car is the observer. As the traffic light changes, so does the behavior of the car, and a single traffic light can direct multiple cars. In software systems, some objects also have a relationship similar to that between traffic lights and cars. Changes in the state or behavior of one object will lead to changes in the state or behavior of other objects, and there will be linkages between them. The so-called pull one hair and move the whole body. In order to better describe this one-to-many linkage between objects, the observer pattern emerges as the times require.

1. Design of multiplayer online battle game

Requirement background: Company M wants to develop a multiplayer online battle game. In the game, multiple players can join the same team to form an alliance. When a member of the team receives an enemy attack, it will send a notification to all other allies. Will respond when notified. The M company developers need to provide a design solution to realize the linkage between team members.

  Through analysis, the developers of M company found that the linkage process between team members in this system can be briefly described as follows:

  Alliance member receives attack => sends notification to allies => allies respond

  If each alliance member needs to hold the ally's information in order to notify each ally in time, the system overhead is relatively large. Therefore, M company developers decided to introduce a new role "Team Control Center" to be responsible for maintaining and managing the information of all members of each team, as shown in the following figure:

Two-observer pattern

  The Observer pattern is one of the most frequently used design patterns, which is used to establish a dependency between objects. When an object changes, it will automatically notify other objects, and other objects will respond accordingly.

2.1 Observer pattern class diagram

  

  Note: Since the Player needs to send a message to the control center, and the control center needs to send a message to all players, there is a problem of mutual reference of header files in the implementation process, and the IControlCenter class is specially introduced.

2.2 Code Implementation

(1) Abstract observer class

class IObserver
{
public:
    IObserver(char *pName = NULL){}
    ~IObserver(){}

    virtual void Help() = 0;
    virtual void BeAttacked(IControlCenter *pControlCenter) = 0;
};

(2) Entity CPlayer class

class Player : public IObserver
{
public:
    Player(char *pName = NULL)
    {
        size_t nLen = strlen(pName);
        memcpy(m_pName, pName, nLen + 1);
    }
    ~Player(){}

    void Help()
    {
        cout << m_pName << " : " << " Hold on, support now! " << endl;
    }

    void BeAttacked(IControlCenter *pControlCenter)
    {
        cout << m_pName << " : " << " I am attacked, request support! " << endl;
        pControlCenter->NotifyObserver(m_pName);
    }

private:
    char m_pName[NAME_LENGTH];
};

(3) Abstract control center

#pragma once

class IControlCenter
{
public:
    IControlCenter(){}
    ~IControlCenter(){}

    virtual void NotifyObserver(char* pName) = 0;
};

(4) Entity Control Center

#pragma once
#include <map>
using namespace std;

#include "IControlCenter.h"
#include "IObserver.h"
class CControlCenter:public IControlCenter
{
public:
    CControlCenter(){}
    ~CControlCenter(){}

    void Regesiter(char* pName, IObserver* pObserver)
    {
        m_ObserverMap[pName] = pObserver;
        cout << "通知:" << pName <<" " << "加入战队!" << endl;
    }

    void UnRegister(char *pName)
    {
        map<char*, IObserver*>::iterator iter;
        for (iter = m_ObserverMap.begin(); iter != m_ObserverMap.end(); iter ++)
        {
            if (0 == strcmp(pName, iter->first))
            {
                m_ObserverMap.erase(iter);
                cout << pName <<" " << "离开战队!" << endl;
                break;
            }
        }
    }

    void NotifyObserver(char* pName)
    {
        cout << " Notice: " << " Allies, " << pName << " under attack " << endl;
        map<char*, IObserver*>::iterator iter;
        for (iter = m_ObserverMap.begin(); iter != m_ObserverMap.end(); iter ++)
        {
            if (0 != strcmp(pName, iter->first))
            {
                IObserver *pPlayer = iter->second;
                pPlayer->Help();
            }
        }
    }

private:
    map<char*, IObserver*> m_ObserverMap;
};

2.3 Testing

(1) Test code

#include "stdio.h"
#include "ControlCenter.h"
#include "IObserver.h"
void main()
{
    CControlCenter *pControlCenter = new CControlCenter();
    IObserver *pPlayer1 = new Player( " Zhang San " );
    IObserver *pPlayer2 = new Player( " Li Si " );
    IObserver *pPlayer3 = new Player("王麻子");
    pControlCenter ->Regesiter( " Zhang San " , pPlayer1);
    pControlCenter ->Regesiter( " Li Si " , pPlayer2);
    pControlCenter->Regesiter("王麻子",pPlayer3);
    pPlayer1->BeAttacked(pControlCenter);
}

(2) Results

 

3. Observer Pattern and MVC

  The observer pattern is also applied in the currently popular MVC (Model-View-Controller) structure, which contains 3 roles: model, view and controller. Among them, the model can correspond to the observation target in the observer pattern, and the view corresponds to the observer, and the controller acts as a mediator between the two. When the data of the model layer changes, the view will automatically change its display content, as shown in the following figure:

Fourth, the observer mode summary

4.1 Main advantages

  (1) Separation of presentation layer and data logic layer can be achieved => various presentation layers can act as specific observers

  (2) Support broadcast communication, the observation target will send a notification to the registered observer object => simplify the difficulty of one-to-many system design

  (3) Adding new observers does not need to modify the original system code =>  satisfy the open-closed principle

4.2 Main disadvantages

  (1) If an observation target has many direct and indirect observers => it will take a lot of time for all observers to receive notification

  (2) If there is a circular dependency between the observer and the observation target => may cause the system to crash

4.3 Application Scenarios

  (1) An abstract model has two aspects, one of which depends on the other => encapsulates it to change and reuse independently

  (2) A change in one object will cause one or more other objects to change, but it is not known how many objects will change => the most familiar stranger

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325740102&siteId=291194637