Programming Languange/디자인 패턴

디자인 패턴 (Design Patterns) - 커맨드 패턴

타자치는 문돌이 2024. 4. 10. 16:12

커맨드 패턴(Command Pattern)은 유사한 동작을 하나의 객체로 묶어 실행하는 디자인 패턴이다.

버튼 클래스를 구현한다고 하자.
버튼은 버튼마다 다른 기능이 있다. 저장, 파일 열기, 편집, 적용, 확인 모두 다른 역할을 한다.
그러나 기능에 맞춰 버튼도 여러 클래스를 만들기에는 기능이 너무 많다.
여러 버튼 객체들이 직접 요청을 보내는 대신, 요청을 보내는 인터페이스를 두고, 이 인터페이스가 기능의 요청을 받아 다른 객체로 보낼 수 있다.

구현

커맨드 패턴은

  • 인터페이스
  • 명령
  • Receiver (수신자)
  • Invoker (호출자)
    로 구성된다.

Receiver

실제로 작업을 수행하는 객체이다.

class Device
{
public:
    void On()
    {
    ...
    }

    void Off()
    {
    ...
    }
};

인터페이스

명령들은 모두 Command 클래스를 상속받는다. execute 함수를 상속받아 공통된 인터페이스를 가진다.

class Command
{
public:
    virtual ~Command() {}
    virtual void execute() = 0;
};

Concrete Command

// Concrete Commands
class CommandOn : public Command {
public:
    CommandOn(Device* device : device(device)) {}

    void execute() override
    {
    device->On();
    }

private:
    Device* device;
};

class CommandOff : public Command {
public:
    CommandOn(Device* device : device(device)) {}

    void execute() override
    {
    device->Off();
    }

private:
    Device* device;
};

Invoker

명령을 실행하는 객체이다. 다른 코드는 인보커에 인자를 넘기며 pressButton을 실행하며 명령을 요청한다.

class Button
{
public:
    void setCommand(Command* command)
    {
    this->command = command;
    }

    void pressButton()
    {
    if (command)
    {
    command->execute();
    }
    }

private:
    Command* command;
}

예시

int main()
{
    Device device;

    CommandOn commandOn(&device);
    CommandOn commandOn(&device);

    Button button;

    button.setCommand(&commandOn);
    button.pressButton();

    button.setCommand(&commandOff);
    button.pressButton();

    return 0;
}

장점

  • 단일 책임원칙을 지킨다. 작업 호출 클래스와 작업 수행 클래스가 분리된다.
  • 개방/폐쇄 원칙을 지킨다. 새 커맨드 도입이 쉽다.
  • 실행 취소/다시 실행과 같은 기능도 구현할 수 있다.
  • 작업의 지연된 실행을 구현할 수 있다.

단점

  • 코드가 복잡해진다.

 

디자인 패턴 (Design Patterns) - Index