C++
[강의] 1월 3일 수업정리
k-codestudy
2025. 1. 3. 17:23
오늘은 커맨드 패턴에 대한 수업을 들었다.
1. 커맨드 패턴 (Command pattern)
1.1 정의
- 커맨드 패턴이란 요청을 객체의 형태로 캡슐화하여 사용자가 보낸 요청을 나중에 이용할 수 있도록 매서드 이름, 매개변수 등 요청에 필요한 정보를 저장 또는 로깅, 취소할 수 있게 하는 패턴이다
1.2 설명
- 커맨드 패턴에는 명령(command), 수신자(receiver), 발동자(invoker), 클라이언트(client)의 네개의 용어가 항상 따른다.
- 커맨드 객체는 수신자 객체를 가지고 있으며, 수신자의 메서드를 호출하고, 이에 수신자는 자신에게 정의된 메서드를 수행한다. 커맨드 객체는 별도로 발동자 객체에 전달되어 명령을 발동하게 한다.
- 발동자 객체는 필요에 따라 명령 발동에 대한 기록을 남길 수 있다.
- 한 발동자 객체에 다수의 커맨드 객체가 전달될 수 있다.
- 클라이언트 객체는 발동자 객체와 하나 이상의 커맨드 객체를 보유한다.
- 클라이언트 객체는 어느 시점에서 어떤 명령을 수행할지를 결정한다.
- 명령을 수행하려면, 클라이언트 객체는 발동자 객체로 커맨드 객체를 전달한다.
즉, 객채를 감싸고 그 감싼 객체를 포인터로 관리해서 사용 ( 커맨드로 한번 더 묶어서 사용할수 있다 )
1.3 UML
1.4 구현
command.h / cpp
#pragma once
#include "receiver.h"
class C_COMMAND abstract
{
public:
C_COMMAND() = default;
virtual ~C_COMMAND() = default;
virtual void excute() abstract;
};
class C_LIGHT_ON : public C_COMMAND
{
private:
C_LIGHT* m_pLight;
public:
C_LIGHT_ON(C_LIGHT* pLight);
void excute() override;
};
class C_LIGHT_OFF : public C_COMMAND
{
private:
C_LIGHT* m_pLight;
public:
C_LIGHT_OFF(C_LIGHT* pLight);
void excute() override;
};
class C_AIRCON_ON : public C_COMMAND
{
private:
C_AIRCON* m_pAircon;
public:
C_AIRCON_ON(C_AIRCON* pAircon);
void excute() override;
};
class C_AIRCON_OFF: public C_COMMAND
{
private:
C_AIRCON* m_pAircon;
public:
C_AIRCON_OFF(C_AIRCON* pAircon);
void excute() override;
};
#include "command.h"
C_LIGHT_ON::C_LIGHT_ON(C_LIGHT* pLight):
m_pLight{}
{
m_pLight = pLight;
}
void C_LIGHT_ON::excute()
{
m_pLight->on();
}
C_LIGHT_OFF::C_LIGHT_OFF(C_LIGHT* pLight):
m_pLight{}
{
m_pLight = pLight;
}
void C_LIGHT_OFF::excute()
{
m_pLight->off();
}
C_AIRCON_ON::C_AIRCON_ON(C_AIRCON* pAircon):
m_pAircon{}
{
m_pAircon = pAircon;
}
void C_AIRCON_ON::excute()
{
m_pAircon->on();
}
C_AIRCON_OFF::C_AIRCON_OFF(C_AIRCON* pAircon) :
m_pAircon{}
{
m_pAircon = pAircon;
}
void C_AIRCON_OFF::excute()
{
m_pAircon->off();
}
C_COMMAND (추상 명령 클래스)
- 설명: 모든 명령 클래스가 상속받는 기본 클래스
- excute()라는 순수 가상 함수(abstract)를 통해 명령의 실행을 정의
- 이 클래스는 실행자(Receiver)와 Invoker(호출자)를 연결하는 인터페이스 역할
명령 클래스 (Concrete Command)
C_COMMAND를 상속받아 구체적인 명령을 구현합니다.
- C_LIGHT_ON, C_LIGHT_OFF: 전등을 켜고 끄는 명령
- C_AIRCON_ON, C_AIRCON_OFF: 에어컨을 켜고 끄는 명령
각 명령 클래스는 내부적으로 Receiver 객체(전등, 에어컨)를 제어하며, 실제로는 이 객체의 메서드(on(), off())를 호출
receiver.h / cpp
#pragma once
#include <stdio.h>
class C_LIGHT
{
public:
void on();
void off();
};
class C_AIRCON
{
public:
void on();
void off();
};
#include "receiver.h"
void C_LIGHT::on()
{
printf("전등 on\n");
}
void C_LIGHT::off()
{
printf("전등 off\n");
}
void C_AIRCON::on()
{
printf("에어컨 on\n");
}
void C_AIRCON::off()
{
printf("에어컨 off\n");
}
실행자(Receiver)
- C_LIGHT: 전등을 제어하는 클래스.
- C_AIRCON: 에어컨을 제어하는 클래스.
실제 동작(전등 켜기/끄기, 에어컨 켜기/끄기)을 정의
RemoteControl.h / cpp
#pragma once
#include "command.h"
class C_REMOTECONTROL
{
private:
C_COMMAND* m_pCommand;
public:
void setCommand(C_COMMAND* pCommand);
void use();
};
#include "RemoteControl.h"
void C_REMOTECONTROL::setCommand(C_COMMAND* pCommand)
{
m_pCommand = pCommand;
}
void C_REMOTECONTROL::use()
{
m_pCommand->excute();
}
호출자(Invoker)
- C_REMOTECONTROL: 리모컨 클래스
- 명령(C_COMMAND*)을 저장하고, 해당 명령을 실행(use())
main.cpp
#include <iostream>
#include "RemoteControl.h"
#include "receiver.h"
int main()
{
C_REMOTECONTROL cRemote{};
C_AIRCON cAircon{};
C_LIGHT cLight{};
C_COMMAND* pCommand = new C_LIGHT_ON(&cLight);
cRemote.setCommand(pCommand);
cRemote.use();
}
동작 흐름
- 전등과 에어컨 객체 생성
- 전등(C_LIGHT)과 에어컨(C_AIRCON) 객체를 생성 - 명령 객체 생성
- 각 Receiver 객체를 기반으로 명령 객체(C_LIGHT_ON,OFF, C_AIRCON_ON,OFF)를 생성 - 명령 설정
- 리모컨(C_REMOTECONTROL)에 명령 객체를 설정 - 명령 실행
- 리모컨의 use()를 호출하면 설정된 명령 객체의 excute()가 실행되고, Receiver의 동작이 수행