# Chapter 06. 커맨드 패턴

LSJ·2026년 8월 22일

1. 커맨드 패턴이란?

커맨드 패턴은 요청을 객체로 캡슐화하는 행동 디자인 패턴이다.

요청을 보내는 객체가 실제 작업을 직접 호출하지 않고, 중간에 있는 명령 객체의 execute()를 호출한다.

호출자(Invoker)
      ↓ execute()
명령(Command)
      ↓ 실제 메서드 호출
수신자(Receiver)

호출자는 명령이 어떻게 처리되는지 알 필요가 없다. 이로 인해 요청을 보내는 객체와 실제 작업을 수행하는 객체의 결합이 느슨해진다.


2. 구성 요소

구성 요소역할
Command명령의 공통 인터페이스
ConcreteCommand특정 작업을 실행하는 명령 객체
Receiver실제 작업을 수행하는 객체
Invoker명령을 저장하고 실행하는 호출자
Client객체를 생성하고 서로 연결하는 역할

리모컨으로 비유하면 리모컨은 Invoker, 조명 켜기 버튼은 Command, 실제 조명은 Receiver가 된다.


3. 간단한 구현

모든 명령은 같은 인터페이스를 구현한다.

public interface Command {
    void execute();
}

실제 작업을 수행할 조명 객체를 만든다.

public class Light {
    public void on() {
        System.out.println("조명을 켭니다.");
    }
}

조명 켜기 명령은 Light 객체를 보관하고 있다가 execute()가 호출되면 실제 작업을 요청한다.

public class LightOnCommand implements Command {
    private final Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
}

리모컨은 구체적인 기기를 알지 못하고 등록된 명령만 실행한다.

public class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }
}
Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();

실행 흐름은 다음과 같다.

리모컨 버튼 클릭
      ↓
LightOnCommand.execute()
      ↓
Light.on()

새로운 기기가 추가되어도 Command를 구현한 명령만 만들면 되므로 리모컨 코드는 변경하지 않아도 된다.


4. 실행 취소(Undo)

명령 객체에 반대 작업을 정의하면 실행 취소 기능도 구현할 수 있다.

public interface Command {
    void execute();
    void undo();
}
public class LightOnCommand implements Command {
    private final Light light;

    @Override
    public void execute() {
        light.on();
    }

    @Override
    public void undo() {
        light.off();
    }
}

호출자가 마지막으로 실행한 명령을 기억하고 있다가 취소 버튼을 누르면 undo()를 호출하면 된다. 여러 단계의 실행 취소가 필요하다면 실행한 명령을 스택에 저장할 수 있다.


정리

커맨드 패턴은 요청을 객체로 만들어 호출자와 실제 작업을 수행하는 수신자를 분리한다.

Invoker → Command → Receiver

요청을 객체로 다루기 때문에 명령을 교체하거나 저장하고, 여러 명령을 조합하거나 실행을 취소할 수 있다. 다만 클래스 수가 늘어나는 만큼 이러한 기능이 실제로 필요한 상황인지 판단한 뒤 적용해야 한다.

0개의 댓글