노트

커맨드 패턴

Command

설계#pattern · 연결된 개념 7개

쉽게 말하면

커맨드 패턴은 할 일을 메모지 한 장에 적어 쌓아 두는 거예요. 적어 둔 메모라서 나중에 실행하거나 줄 세워 두거나, 쌓인 순서를 거꾸로 따라가며 되돌릴 수도 있어요.

비유가 깨지는 곳 메모지는 공짜지만 코드의 명령 객체는 복잡성이라는 값을 치러요. 파울러는 대부분 그냥 함수를 고르고, 되돌리기처럼 함수로는 못 하는 기능이 필요할 때만 명령을 쓴다고 해요.

요청이나 작업을 실행 가능한 객체로 포장하는 패턴. 작업을 값처럼 저장·전달·대기열에 넣을 수 있게 되고, 되돌리기 같은 부가 연산을 붙일 수 있다.

interface Command { execute(): void; undo(): void }
 
class InsertText implements Command {
  constructor(private doc: Doc, private pos: number, private text: string) {}
  execute() { this.doc.insert(this.pos, this.text) }
  undo() { this.doc.remove(this.pos, this.text.length) }
}
 
const history: Command[] = []
function run(cmd: Command) { cmd.execute(); history.push(cmd) }
function undo() { history.pop()?.undo() }
  • 편집기의 실행 취소·다시 실행, 작업 대기열, 실행 기록, 매크로가 전형적인 사용처다
  • Redux의 액션처럼 "무엇을 할지"를 데이터로 표현하는 방식도 같은 계열이다(useReducer)

리팩터링으로 오가기

『리팩터링』에는 함수를 명령으로 바꾸기(Replace Function with Command, 1판의 "메서드를 메서드 객체로"(Replace Method with Method Object))와 그 반대가 짝으로 있다. 긴 함수의 지역 변수를 필드로 옮기면 함수를 여러 메서드로 쪼개기 쉬워진다. 하지만 유연성의 대가는 복잡성이다. 파울러는 일급 함수(First-Class Function)와 명령 중 고르라면 95%는 함수를 고르고, 함수로는 얻을 수 없는 기능(되돌리기 등)이 필요할 때만 명령을 쓴다고 한다. 로직이 단순한 명령 객체는 평범한 함수로 되돌린다.

이름은 비슷하지만 명령-질의 분리의 "명령"은 상태를 바꾸는 함수를 뜻하는 다른 개념이다. 행동 패턴 전체는 행동 패턴.

출처: Command — Refactoring.Guru · 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · Replace Function with Command · Replace Command with Function

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 상태 패턴

    객체의 행동이 현재 상태에 따라 달라질 때, 상태마다 별도 객체를 두고 현재 상태 객체에 행동을 맡기는 패턴. 상태별 조건문이 메서드마다 반복되는 문제를 푼다.

  • 함수·필드 옮기기

    함수나 필드를 더 자연스러운 맥락(모듈·클래스)으로 옮기는 리팩터링. 좋은 설계의 핵심인 모듈성(Modularity), 즉 어딘가를 고칠 때 관련된 작은 부분만 이해하면 되게 하는 능력을 키운다.

  • 팩토리 메서드 패턴

    객체 생성을 생성자 호출 대신 전용 메서드(또는 함수)에 맡기는 패턴. GoF(Gang of Four)의 원래 형태는 상위 클래스가 생성 메서드를 선언하고 하위 클래스가 어떤 제품을 만들지 정하는 구조지만, 실무에서는 "생성을 감싸는 함수" 전반을 넓게 가리키기도 한다.

  • 변수·컬렉션 캡슐화

    넓은 범위에서 쓰이는 데이터에 직접 접근하지 못하게 하고, 읽고 쓰는 함수를 통해서만 다루게 하는 리팩터링. 데이터를 옮기거나 바꿀 때 고쳐야 할 곳이 접근 함수 한 곳으로 좁아진다.

  • 전략 패턴

    같은 목적을 가진 여러 알고리즘을 각각 별도 객체(또는 함수)로 빼고, 실행할 때 그중 하나를 골라 끼우는 패턴. 호출하는 쪽은 공통 인터페이스만 안다.

보기 옵션