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();
}

 

동작 흐름

  1. 전등과 에어컨 객체 생성
    - 전등(C_LIGHT)과 에어컨(C_AIRCON) 객체를 생성
  2. 명령 객체 생성
    - 각 Receiver 객체를 기반으로 명령 객체(C_LIGHT_ON,OFF, C_AIRCON_ON,OFF)를 생성
  3. 명령 설정
    - 리모컨(C_REMOTECONTROL)에 명령 객체를 설정
  4. 명령 실행
    - 리모컨의 use()를 호출하면 설정된 명령 객체의 excute()가 실행되고, Receiver의 동작이 수행