Command Pattern

commnad pattern은 명령을 패턴화 시킨 것으로 구체적으로 이야기 하자면 함수나 메쏘드를 일반화 시킨다.

주 사용 용도는 문자열에 의해 명령을 내릴때, Undo, Redo 기능을 구현 할 때 사용된다.

command pattern을 사용하면 command에 따른 클래스가 많아지는 단점이 있다.

UML을 봐도 이해하는게 쉽지 않다. 용어를 알아보고 코드를 봐야 눈에 들어 올 것이다.

<용어 정리>

client : 어플리케이션, 메인 루틴
Receiver : 실행할 함수나 메쏘드이다.
Command : 명령 인터페이스
ConcreteCommand : Command를 상속해 Receiver를 실행한다.
Invoker : Command 관리자나 Command를 실행할 수 있는 서버이다.

< 예제 코드 >
예제를 실행 하면, CommandManager에서 큐로 저장된 명령들을 다시 한번 반복하여 실행 한다.
예제이다 보니 Undo에 사용하기에는 완벽하지는 않지만 기본 개념은 이해 할 수 있을 것이다.

client : 어플리케이션, 메인 루틴
Receiver : CFog::Move(), CObject::Move(), CObject::Scale()
Command : ICommand
ConcreteCommand : CommandMoveFog, CommandMoveObject, CommandScaleObject
Invoker : CommandManager의 메쏘드들

#include <stdio.h>

#include <vector>

#include <string>

#include <queue>

#include <iostream>

 

 

class ICommand

{

public:

    virtual void Execute() = 0;

};

 

class CommandMoveFog;

class CommandMoveObject;

class CommandScaleObject;

 

 

class CFog

{

public:

    void CTextureFog()

    {

        m_fx = 0.0f; m_fy = 0.0f; m_fRadius = 0.0f;

    }

    void Move(float fx, float fy, float fRadius)

    {

        m_fx = fx;   m_fy = fy;   m_fRadius = fRadius;   

        std::cout << "CFog::Move(" << fx <<  ",  " << fy << ", " << fRadius << ")" << std::endl;

    }

 

    float m_fx, m_fy, m_fRadius;

};

 

 

class CObject

{

public:

    CObject()

    {

        m_fx = 0.0f; m_fy = 0.0f; m_fz = 0.0f;  m_fScale = 0.0f;

    }

 

    void Move(float fx, float fy, float fz)

    {

        m_fx = fx;   m_fy = fy;   m_fz = fz;

        std::cout << "CObject::Move(" << fx  << ",  " << fy << ", " << fz << ")" << std::endl;

    }

 

    void Scale(float fScale)

    {

        m_fScale = fScale;

        std::cout << "CObject::Move(" << fScale << ")" << std::endl;

    }

 

    float m_fx, m_fy, m_fz, m_fScale;

};

 

 

class CommandMoveFog : public ICommand

{

    //여기에 저장하고자 하는 오브젝트나 오브젝트의 인터페이스를 저장한다.

    //오브젝트 삭제를 고려해야 한다면, 포인터보다는 값이나 정보를 넣는다.

    CFog* m_pFog;

    float    m_fx, m_fy, m_fRadius;

 

public:

    CommandMoveFog(CFog* pFog, float fx, float fy, float fRadius) :

      m_pFog(pFog), m_fx(fx), m_fy(fy), m_fRadius(fRadius)  {}

 

    virtual void Execute()

    {

        m_pFog->Move(m_fx, m_fy, m_fRadius);

    }

};

 

class CommandMoveObject : public ICommand

{

    CObject* m_pObject;

    float    m_fx, m_fy, m_fz;

public:

    CommandMoveObject(CObject* pObject, float fx, float fy, float fz) :

      m_pObject(pObject), m_fx(fx), m_fy(fy), m_fz(fz) {}

 

 

    virtual void Execute()

    {

        m_pObject->Move(m_fx, m_fy, m_fz);

    }

};

 

class CommandScaleObject : public ICommand

{

    CObject* m_pObject;

    float    m_fScale;

public:

    CommandScaleObject(CObject* pObject, float fScale) :

      m_pObject(pObject), m_fScale(fScale) {}

 

    void Execute()

    {

        m_pObject->Scale(m_fScale);

    }

};

 

 

class CommandManager

{

    std::queue< ICommand * >  m_pCommandQueue;

public:

    CommandManager() {}

 

    void MoveFog(CFog* pFog, float fx, float fy, float fRadius)

    {

        m_pCommandQueue.push(new CommandMoveFog(pFog, fx, fy, fRadius));

    }

    void MoveObject(CObject* pObject, float fx, float fy, float fz)

    {

        m_pCommandQueue.push(new CommandMoveObject(pObject, fx, fy, fz));   

    }

    void ScaleObject(CObject* pObject, float fScale)

    {

        m_pCommandQueue.push(new CommandScaleObject(pObject, fScale));   

    }

 

    bool Update()

    {

        bool bUpdate = false;

        if(!m_pCommandQueue.empty())

        {

            ICommand * pCommand = m_pCommandQueue.front();

            pCommand->Execute();

            delete pCommand;

            m_pCommandQueue.pop();

            bUpdate = true;

        }

 

        return bUpdate;

    }

};

 

 

void main()

{

    CommandManager command;

    CFog fog;

    CObject object;

 

    fog.Move( 10.0f, 10.0f, 100.0f);

    command.MoveFog( &fog, 10.0f, 10.0f, 100.0f);

 

    object.Move( 1000.0f, 1000.0f, 0.0f);

    command.MoveObject( &object, 1000.0f, 1000.0f, 0.0f);

 

    object.Scale( 100.0f);

    command.ScaleObject( &object, 100.0f);

 

    object.Scale( 1.0f);

    command.ScaleObject( &object, 1.0f);

 

    std::cout << "-------------------Run Command Pattern-------------------" << std::endl;

    while(command.Update());

 

    getchar();

}

소스 : command_pattern.cpp