프로그램에서 “무엇을 실행할 것인가”를 다루다 보면, 단순 함수 호출로는 부족해지는 순간이 있습니다. 요청을 나중에 실행해야 하거나, 큐에 넣어야 하거나, 이력으로 남겨야 하거나, 취소/재실행을 다루고 싶을 때가 그렇습니다. 커맨드 패턴은 이런 문제를 설명할 때 자주 등장하는 패턴입니다.
이 글에서는 아래 내용을 정리합니다.
- 커맨드 패턴이 무엇인지
- 왜 요청을 객체로 감싸는지
- 어떤 상황에서 유용한지
- 큐잉, 재실행, 취소와 어떻게 연결되는지
핵심은 커맨드 패턴은 실행할 요청을 객체로 표현해서, 실행 시점과 실행 주체를 더 유연하게 다룰 수 있게 만드는 구조라는 점입니다.
커맨드 패턴이란 무엇인가
커맨드 패턴은 “실행할 작업”을 하나의 객체로 다루는 방식입니다.
즉:
- 무엇을 할지
- 어떤 데이터로 할지
를 객체 안에 담아두고, 나중에 실행할 수 있게 합니다.
왜 유용할까
요청을 그냥 즉시 함수로 실행하면:
- 나중에 실행하기 어렵고
- 큐에 넣기 어렵고
- 이력 관리가 어렵고
- 공통 처리 로직을 얹기 어렵습니다
반대로 요청을 객체로 만들면 실행을 데이터처럼 다룰 수 있습니다.
어떤 상황에서 잘 맞을까
- 버튼 클릭 액션
- 작업 큐
- undo/redo
- 배치 실행
- 실행 이력 저장
즉, “요청” 자체를 독립적인 단위로 다뤄야 할 때 특히 잘 맞습니다.
큐잉과는 왜 잘 어울릴까
커맨드 객체는 실행해야 할 정보가 묶여 있으므로:
- 큐에 넣고
- 나중에 꺼내서 실행하고
- 실패 시 재시도하고
같은 흐름과 잘 어울립니다.
그래서 백그라운드 작업이나 비동기 처리 구조를 설명할 때도 자주 연결됩니다.
자주 하는 오해
1. 함수가 있는데 왜 굳이 객체로 감싸나
즉시 실행만 필요한 코드라면 과할 수 있지만, 실행을 저장하고 전달해야 하면 꽤 큰 차이가 납니다.
2. 커맨드 패턴은 UI 코드에서만 쓴다
작업 큐, 배치, 자동화 흐름에서도 충분히 잘 맞습니다.
3. 모든 액션은 커맨드 패턴으로 만들어야 한다
항상 그럴 필요는 없습니다. 요청을 독립 단위로 다뤄야 하는 상황에서 특히 가치가 큽니다.
Simple Example
interface Command {
execute(): void;
}
class SendEmailCommand implements Command {
constructor(private email: string) {}
execute(): void {
console.log(`Send email to ${this.email}`);
}
}
class CommandQueue {
private commands: Command[] = [];
add(command: Command): void {
this.commands.push(command);
}
run(): void {
this.commands.forEach((command) => command.execute());
}
}
const queue = new CommandQueue();
queue.add(new SendEmailCommand('team@example.com'));
queue.run();
The request is turned into an object, so we can queue it, delay it, log it, or swap the executor later.
FAQ
Q. 입문자는 어디서 커맨드 패턴을 떠올리면 좋을까
나중에 실행, 반복 실행, 취소, 큐잉 같은 요구가 보일 때 떠올리기 좋습니다.
Q. 전략 패턴과는 어떻게 다른가
전략은 행동 방식 교체, 커맨드는 실행 요청 자체를 객체화하는 데 더 가깝습니다.
Q. 커맨드 패턴은 이벤트와 같은가
비슷하게 느껴질 수 있지만, 커맨드는 실행 가능한 요청 단위라는 점에 더 초점이 있습니다.
Read Next
- 생성과 조립은 팩토리 패턴 가이드와 같이 보면 좋습니다.
- 상태 변화 알림은 옵저버 패턴 가이드와 비교해보면 차이가 잘 보입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.