diff --git "a/changyu/06.\354\273\244\353\247\250\353\223\234_\355\214\250\355\204\264.md" "b/changyu/06.\354\273\244\353\247\250\353\223\234_\355\214\250\355\204\264.md"
new file mode 100644
index 0000000..3f072f0
--- /dev/null
+++ "b/changyu/06.\354\273\244\353\247\250\353\223\234_\355\214\250\355\204\264.md"
@@ -0,0 +1,541 @@
+# Week 6. 커맨드(Command) 패턴
+
+## 학습 정보
+
+- **주차**: 6주차
+- **챕터**: Chapter 06 — 호출 캡슐화하기
+- **패턴명**: 커맨드 패턴 (Command Pattern)
+- **학습일**: 2025-03-24
+- **학습 범위**: Chapter 06 전체
+
+---
+
+## 학습 목표
+
+- 요청(메서드 호출)을 객체로 캡슐화하는 커맨드 패턴의 구조와 동작 원리를 이해한다.
+- 인보커와 리시버를 분리하여 느슨한 결합을 달성하는 방법을 학습한다.
+- 작업 취소(Undo), 매크로 커맨드, 작업 큐 등 커맨드 패턴의 다양한 활용법을 익힌다.
+
+---
+
+## 핵심 개념
+
+### 패턴이 해결하는 문제
+
+홈 오토메이션 리모컨 API를 설계하는 상황이다.
+
+리모컨에는 7개의 슬롯이 있고, 각 슬롯마다 ON/OFF 버튼이 있다.
+
+각 슬롯에는 조명, 선풍기, 오디오, TV, 욕조 등 다양한 가전제품을 연결할 수 있다.
+
+문제는 협력 업체에서 제공하는 클래스들의 인터페이스가 제각각이라는 점이다.
+
+`Light`에는 `on()`/`off()`가, `CeilingFan`에는 `high()`/`medium()`/`low()`/`off()`가, `Stereo`에는 `on()`/`off()`/`setCd()`/`setVolume()` 등이 있다.
+
+공통 인터페이스가 없고, 앞으로 더 많은 클래스가 추가될 수 있다.
+
+리모컨 코드에서 각 기기의 구체적인 메서드를 직접 호출하면 다음과 같은 문제가 발생한다.
+
+- 새로운 가전제품이 추가될 때마다 리모컨 코드를 수정해야 한다.
+- 리모컨이 각 기기의 세부 동작 방식을 알아야 한다(강한 결합).
+- 작업 취소(Undo) 같은 공통 기능을 구현하기 어렵다.
+
+커맨드 패턴은 **요청 자체를 객체로 캡슐화**하여 인보커(리모컨)와 리시버(가전제품)를 완전히 분리한다.
+
+### 패턴의 정의
+
+> **커맨드 패턴(Command Pattern)** 을 사용하면 요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화할 수 있다.
+>
+> 이러면 요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 기능을 사용할 수 있다.
+
+핵심 아이디어는 "객체마을 식당" 비유로 이해할 수 있다.
+
+- **고객(Client)**: 주문을 생성한다.
+- **주문서(Command)**: 주문 내용을 캡슐화한다. `orderUp()` 메서드 하나로 식사 준비를 요청한다.
+- **종업원(Invoker)**: 주문서를 받아서 `orderUp()`을 호출한다. 주문서에 무슨 내용이 있는지, 누가 요리를 하는지 전혀 알 필요가 없다.
+- **주방장(Receiver)**: 실제로 식사를 준비하는 방법을 알고 있다.
+
+종업원과 주방장이 완전히 분리되어 있듯이, 커맨드 패턴에서도 인보커와 리시버가 분리된다.
+
+### 주요 구성요소
+
+- **Command (인터페이스)**: 모든 커맨드 객체가 구현하는 인터페이스. `execute()`와 `undo()` 메서드를 정의한다.
+- **ConcreteCommand (LightOnCommand 등)**: Command를 구현한 구상 클래스. 리시버와 행동 사이의 바인딩을 정의한다. `execute()` 호출 시 리시버의 메서드를 호출하여 실제 작업을 수행한다.
+- **Invoker (RemoteControl)**: 커맨드 객체를 저장하고, 특정 시점에 `execute()`를 호출하여 요청을 실행한다. 커맨드가 어떤 일을 하는지는 전혀 모른다.
+- **Receiver (Light, CeilingFan 등)**: 요구 사항을 수행할 때 어떤 일을 처리해야 하는지 알고 있는 객체다.
+- **Client**: ConcreteCommand를 생성하고 Receiver를 설정한다.
+- **NoCommand (널 객체)**: 아무 일도 하지 않는 커맨드 클래스. 슬롯에 커맨드가 할당되지 않았을 때 null 체크 대신 사용한다.
+
+---
+
+## 패턴 구조
+
+### UML 다이어그램
+
+```mermaid
+classDiagram
+ direction TB
+
+ class Command {
+ <>
+ +execute(): void
+ +undo(): void
+ }
+
+ class ConcreteCommand {
+ -receiver: Receiver
+ +execute(): void
+ +undo(): void
+ }
+
+ class Invoker {
+ -command: Command
+ +setCommand(cmd: Command): void
+ +executeCommand(): void
+ }
+
+ class Receiver {
+ +action(): void
+ }
+
+ class Client
+
+ Client --> Receiver : creates
+ Client --> ConcreteCommand : creates
+ ConcreteCommand ..|> Command
+ ConcreteCommand --> Receiver : delegates to
+ Invoker --> Command : calls execute()
+```
+
+### 동작 방식
+
+1. **Client**가 Receiver(예: `Light`)를 생성하고, 해당 Receiver를 전달하여 ConcreteCommand(예: `LightOnCommand`)를 생성한다.
+2. Client가 Invoker(예: `RemoteControl`)의 `setCommand()`를 호출하여 커맨드 객체를 슬롯에 저장한다.
+3. 사용자가 버튼을 누르면 Invoker가 해당 슬롯의 커맨드 객체의 `execute()`를 호출한다.
+4. ConcreteCommand의 `execute()` 내부에서 Receiver의 메서드(예: `light.on()`)를 호출하여 실제 작업이 수행된다.
+5. Invoker는 어떤 Receiver가 어떤 작업을 수행하는지 전혀 알지 못한다. 커맨드 인터페이스의 `execute()`만 호출할 뿐이다.
+
+---
+
+## 코드 예제
+
+### 예제 상황
+
+홈 오토메이션 리모컨 시스템이다.
+
+리모컨에는 7개의 슬롯이 있고, 각 슬롯에는 ON/OFF 버튼이 있다.
+
+조명, 선풍기, 오디오 등 다양한 가전제품을 각 슬롯에 할당하여 제어한다.
+
+작업 취소(Undo) 버튼도 지원해야 하며, 여러 장치를 한 번에 제어하는 매크로 커맨드도 필요하다.
+
+### 커맨드 인터페이스와 NoCommand
+
+```typescript
+/** 모든 커맨드가 구현하는 인터페이스 */
+interface Command {
+ execute(): void;
+ undo(): void;
+}
+
+/** 널 객체 — 아무 일도 하지 않는 커맨드 */
+class NoCommand implements Command {
+ public execute() {}
+
+ public undo() {}
+}
+```
+
+`NoCommand`는 널 객체(Null Object) 패턴의 적용이다.
+
+슬롯에 커맨드가 할당되지 않았을 때 `null` 체크를 하는 대신 `NoCommand`를 기본값으로 넣어두면, `execute()`를 호출해도 아무 일도 일어나지 않으므로 안전하다.
+
+### 리시버: 가전제품 클래스
+
+```typescript
+class Light {
+ constructor(private location: string) {}
+
+ public on() {
+ console.log(`${this.location} 조명이 켜졌습니다`);
+ }
+
+ public off() {
+ console.log(`${this.location} 조명이 꺼졌습니다`);
+ }
+}
+
+class CeilingFan {
+ static readonly HIGH = 3;
+ static readonly MEDIUM = 2;
+ static readonly LOW = 1;
+ static readonly OFF = 0;
+
+ private speed = CeilingFan.OFF;
+
+ constructor(private location: string) {}
+
+ public high() {
+ this.speed = CeilingFan.HIGH;
+ console.log(`${this.location} 선풍기 속도가 HIGH로 설정되었습니다`);
+ }
+
+ public medium() {
+ this.speed = CeilingFan.MEDIUM;
+ console.log(`${this.location} 선풍기 속도가 MEDIUM으로 설정되었습니다`);
+ }
+
+ public low() {
+ this.speed = CeilingFan.LOW;
+ console.log(`${this.location} 선풍기 속도가 LOW로 설정되었습니다`);
+ }
+
+ public off() {
+ this.speed = CeilingFan.OFF;
+ console.log(`${this.location} 선풍기가 꺼졌습니다`);
+ }
+
+ public getSpeed() {
+ return this.speed;
+ }
+}
+
+class Stereo {
+ constructor(private location: string) {}
+
+ public on() {
+ console.log(`${this.location} 오디오가 켜졌습니다`);
+ }
+
+ public off() {
+ console.log(`${this.location} 오디오가 꺼졌습니다`);
+ }
+
+ public setCd() {
+ console.log(`${this.location} 오디오에서 CD가 재생됩니다`);
+ }
+
+ public setVolume(volume: number) {
+ console.log(`${this.location} 오디오의 볼륨이 ${volume}로 설정되었습니다`);
+ }
+}
+```
+
+### 구상 커맨드: 조명
+
+```typescript
+class LightOnCommand implements Command {
+ constructor(private light: Light) {}
+
+ public execute() {
+ this.light.on();
+ }
+
+ public undo() {
+ // execute()의 반대 작업
+ this.light.off();
+ }
+}
+
+class LightOffCommand implements Command {
+ constructor(private light: Light) {}
+
+ public execute() {
+ this.light.off();
+ }
+
+ public undo() {
+ this.light.on();
+ }
+}
+```
+
+### 구상 커맨드: 선풍기 (상태를 사용하는 Undo)
+
+선풍기처럼 단순히 on/off가 아닌 여러 단계의 상태를 가진 기기의 경우, `undo()` 구현 시 이전 상태를 저장해 두어야 한다.
+
+```typescript
+class CeilingFanHighCommand implements Command {
+ private prevSpeed: number = CeilingFan.OFF;
+
+ constructor(private ceilingFan: CeilingFan) {}
+
+ public execute() {
+ // 작업 취소를 위해 현재 속도를 저장한 후 새 속도로 변경
+ this.prevSpeed = this.ceilingFan.getSpeed();
+ this.ceilingFan.high();
+ }
+
+ public undo() {
+ // 이전 속도로 복원
+ switch (this.prevSpeed) {
+ case CeilingFan.HIGH:
+ this.ceilingFan.high();
+ break;
+ case CeilingFan.MEDIUM:
+ this.ceilingFan.medium();
+ break;
+ case CeilingFan.LOW:
+ this.ceilingFan.low();
+ break;
+ case CeilingFan.OFF:
+ this.ceilingFan.off();
+ break;
+ }
+ }
+}
+
+class CeilingFanOffCommand implements Command {
+ private prevSpeed: number = CeilingFan.OFF;
+
+ constructor(private ceilingFan: CeilingFan) {}
+
+ public execute() {
+ this.prevSpeed = this.ceilingFan.getSpeed();
+ this.ceilingFan.off();
+ }
+
+ public undo() {
+ switch (this.prevSpeed) {
+ case CeilingFan.HIGH:
+ this.ceilingFan.high();
+ break;
+ case CeilingFan.MEDIUM:
+ this.ceilingFan.medium();
+ break;
+ case CeilingFan.LOW:
+ this.ceilingFan.low();
+ break;
+ case CeilingFan.OFF:
+ this.ceilingFan.off();
+ break;
+ }
+ }
+}
+```
+
+### 구상 커맨드: 오디오 (여러 메서드를 순서대로 호출)
+
+```typescript
+class StereoOnWithCDCommand implements Command {
+ constructor(private stereo: Stereo) {}
+
+ public execute() {
+ // 오디오를 켜고 CD를 재생하고 볼륨을 설정하는 일련의 동작을 하나로 캡슐화
+ this.stereo.on();
+ this.stereo.setCd();
+ this.stereo.setVolume(11);
+ }
+
+ public undo() {
+ this.stereo.off();
+ }
+}
+```
+
+### 인보커: 리모컨 (Undo 지원)
+
+```typescript
+class RemoteControl {
+ private onCommands: Command[];
+ private offCommands: Command[];
+ private undoCommand: Command;
+
+ constructor() {
+ const noCommand = new NoCommand();
+
+ // 7개 슬롯을 NoCommand로 초기화
+ this.onCommands = Array(7)
+ .fill(null)
+ .map(() => noCommand);
+ this.offCommands = Array(7)
+ .fill(null)
+ .map(() => noCommand);
+ this.undoCommand = noCommand;
+ }
+
+ public setCommand(slot: number, onCommand: Command, offCommand: Command) {
+ this.onCommands[slot] = onCommand;
+ this.offCommands[slot] = offCommand;
+ }
+
+ public onButtonWasPushed(slot: number) {
+ this.onCommands[slot].execute();
+ // 마지막으로 실행한 커맨드를 Undo용으로 저장
+ this.undoCommand = this.onCommands[slot];
+ }
+
+ public offButtonWasPushed(slot: number) {
+ this.offCommands[slot].execute();
+ this.undoCommand = this.offCommands[slot];
+ }
+
+ public undoButtonWasPushed() {
+ this.undoCommand.undo();
+ }
+
+ public toString() {
+ let result = "\n------ 리모컨 --------\n";
+
+ for (let i = 0; i < this.onCommands.length; i++) {
+ result += `[slot ${i}] ${this.onCommands[i].constructor.name}\t${this.offCommands[i].constructor.name}\n`;
+ }
+ result += `[undo] ${this.undoCommand.constructor.name}\n`;
+
+ return result;
+ }
+}
+```
+
+### 매크로 커맨드: 여러 동작을 한 번에 실행
+
+버튼 하나로 조명, 오디오, TV 등을 동시에 제어하는 "파티 모드" 같은 기능이다.
+
+```typescript
+class MacroCommand implements Command {
+ constructor(private commands: Command[]) {}
+
+ public execute() {
+ for (const command of this.commands) {
+ command.execute();
+ }
+ }
+
+ public undo() {
+ // 실행의 역순으로 취소
+ for (let i = this.commands.length - 1; i >= 0; i--) {
+ this.commands[i].undo();
+ }
+ }
+}
+```
+
+### 실행 코드
+
+```typescript
+const remoteControl = new RemoteControl();
+
+// 리시버 생성
+const livingRoomLight = new Light("거실");
+const kitchenLight = new Light("주방");
+const ceilingFan = new CeilingFan("거실");
+const stereo = new Stereo("거실");
+
+// 커맨드 생성
+const livingRoomLightOn = new LightOnCommand(livingRoomLight);
+const livingRoomLightOff = new LightOffCommand(livingRoomLight);
+const kitchenLightOn = new LightOnCommand(kitchenLight);
+const kitchenLightOff = new LightOffCommand(kitchenLight);
+const ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
+const ceilingFanOff = new CeilingFanOffCommand(ceilingFan);
+const stereoOnWithCD = new StereoOnWithCDCommand(stereo);
+const stereoOff = new StereoOffCommand(stereo);
+
+// 슬롯에 커맨드 할당
+remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
+remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
+remoteControl.setCommand(2, ceilingFanHigh, ceilingFanOff);
+remoteControl.setCommand(3, stereoOnWithCD, stereoOff);
+
+// 버튼 누르기
+remoteControl.onButtonWasPushed(0); // 거실 조명이 켜졌습니다
+remoteControl.offButtonWasPushed(0); // 거실 조명이 꺼졌습니다
+remoteControl.undoButtonWasPushed(); // 거실 조명이 켜졌습니다 (Undo)
+
+// 매크로 커맨드: 파티 모드
+const partyOn: Command[] = [livingRoomLightOn, stereoOnWithCD];
+const partyOff: Command[] = [livingRoomLightOff, stereoOff];
+const partyOnMacro = new MacroCommand(partyOn);
+const partyOffMacro = new MacroCommand(partyOff);
+
+remoteControl.setCommand(4, partyOnMacro, partyOffMacro);
+remoteControl.onButtonWasPushed(4); // 거실 조명 + 오디오 동시 켜짐
+```
+
+### 코드 설명
+
+- **리모컨(Invoker)은 가전제품(Receiver)을 전혀 모른다.** `execute()`만 호출할 뿐, 그 뒤에서 어떤 객체가 무슨 일을 하는지 알 필요가 없다. 새로운 가전제품이 추가되어도 리모컨 코드는 변경하지 않아도 된다.
+- **NoCommand(널 객체)**: 모든 슬롯을 `NoCommand`로 초기화하여 `null` 체크 없이 안전하게 `execute()`를 호출할 수 있다.
+- **Undo 구현**: 단순한 on/off 토글은 반대 메서드를 호출하면 되지만, 선풍기처럼 여러 상태를 가진 경우 `execute()` 호출 전에 이전 상태를 저장해 두어야 한다.
+- **MacroCommand**: Command 배열을 받아 순서대로 실행한다. `undo()` 시에는 역순으로 취소한다. Command 인터페이스만 구현하면 되므로 리모컨 코드를 전혀 바꾸지 않고 매크로를 추가할 수 있다.
+- **람다 표현식 활용**: TypeScript에서는 간단한 커맨드를 화살표 함수로 대체할 수 있다. 단, Command 인터페이스의 추상 메서드가 `execute()` 하나뿐일 때만 가능하고 `undo()`가 필요하면 클래스를 사용해야 한다.
+
+---
+
+## 구현 방식 비교
+
+커맨드 패턴을 도입하기 전과 후의 리모컨 설계를 비교한다.
+
+| 구분 | 커맨드 패턴 없이 (직접 호출) | 커맨드 패턴 적용 |
+| ------------------ | ------------------------------------------------- | ---------------------------------------------- |
+| 리모컨-기기 결합도 | 강함 — 리모컨이 각 기기의 메서드를 직접 알아야 함 | 느슨함 — 리모컨은 `execute()`만 호출 |
+| 새 기기 추가 시 | 리모컨 코드 수정 필요 | 새 커맨드 클래스만 추가 |
+| 작업 취소 (Undo) | 구현 어려움 (각 기기별로 별도 로직 필요) | `undo()` 메서드로 일관되게 구현 |
+| 매크로 기능 | 별도 구현 필요 | MacroCommand로 커맨드 조합 |
+| 로그/큐 지원 | 어려움 | 커맨드 객체를 큐에 저장하거나 로그로 기록 가능 |
+
+---
+
+## 실전 활용
+
+### 언제 사용하면 좋을까?
+
+- 요청을 보내는 쪽과 요청을 처리하는 쪽을 분리해야 할 때
+- 작업 취소(Undo/Redo) 기능이 필요할 때
+- 요청을 큐에 저장하거나 로그로 기록해야 할 때 (작업 큐, 트랜잭션 로그 등)
+- 여러 작업을 하나로 묶어 매크로로 실행해야 할 때
+
+### 장단점
+
+**장점**
+
+- 인보커와 리시버를 완전히 분리하여 느슨한 결합을 달성한다.
+- 새로운 커맨드를 추가할 때 기존 코드를 변경할 필요가 없다(OCP 준수).
+- 작업 취소(Undo), 작업 큐, 로그 기록, 매크로 등 다양한 부가 기능을 자연스럽게 구현할 수 있다.
+- 커맨드 객체를 일급 객체(first-class object)로 다룰 수 있어 저장, 전달, 조합이 자유롭다.
+
+**단점**
+
+- 간단한 요청에도 커맨드 클래스를 만들어야 하므로 클래스 수가 증가한다.
+- 리시버와 커맨드 사이의 관계를 설정하는 클라이언트 코드가 복잡해질 수 있다.
+
+### 실제 적용 사례
+
+- **작업 큐 (Job Queue)**: 커맨드 객체를 큐에 넣고, 워커 스레드가 하나씩 꺼내서 `execute()`를 호출한다. 큐는 커맨드가 어떤 작업을 수행하는지 전혀 알 필요가 없다. JavaScript의 이벤트 루프와 태스크 큐가 이 구조와 유사하다.
+- **트랜잭션 로그/복구**: 커맨드를 실행할 때마다 디스크에 기록해 두고, 시스템 장애 후 로그를 다시 로딩하여 `execute()`를 순서대로 재실행하면 상태를 복구할 수 있다.
+- **텍스트 에디터의 Undo/Redo**: 사용자의 편집 동작(입력, 삭제, 서식 변경 등)을 각각 커맨드 객체로 만들고 스택에 쌓는다. Undo 시 스택에서 꺼내 `undo()`를 호출한다.
+- **Redux의 Action**: Redux에서 상태 변경 요청을 `{ type: 'INCREMENT', payload: 1 }` 같은 액션 객체로 캡슐화하는 구조가 커맨드 패턴의 변형이다. 액션 자체는 "무엇을 할지"만 기술하고, 리듀서가 실제 처리를 담당한다.
+- **Express의 미들웨어 체인**: 각 미들웨어가 요청을 처리하는 커맨드 역할을 하며, `next()`를 통해 다음 커맨드로 제어를 넘긴다.
+
+---
+
+## 핵심 정리
+
+- 커맨드 패턴은 요청(메서드 호출)을 객체로 캡슐화하여 인보커와 리시버를 완전히 분리한다. 인보커는 `execute()`만 호출하면 되고, 그 뒤에서 어떤 객체가 무슨 작업을 하는지 알 필요가 없다.
+- Command 인터페이스에 `undo()` 메서드를 추가하면 작업 취소 기능을 쉽게 구현할 수 있다. 단순 토글이 아닌 경우(선풍기 속도 등) 이전 상태를 저장해 두어야 한다.
+- MacroCommand로 여러 커맨드를 하나로 묶어 실행할 수 있다. 커맨드 인터페이스만 구현하면 되므로 기존 인보커 코드를 수정할 필요가 없다.
+- 커맨드 패턴은 작업 큐, 트랜잭션 로그, Undo/Redo 히스토리 등 "요청을 나중에 실행하거나 기록해야 하는" 다양한 상황에서 활용된다.
+
+---
+
+## 함께 등장한 디자인 원칙
+
+| 원칙 | 이 패턴에서의 적용 |
+| ------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
+| 바뀌는 부분은 캡슐화한다 | 각 기기의 구체적인 동작 방식(바뀌는 부분)을 커맨드 객체로 캡슐화하여 리모컨 코드에서 분리 |
+| 구현보다는 인터페이스에 맞춰서 프로그래밍한다 | 리모컨(Invoker)은 Command 인터페이스에만 의존하며, 구상 커맨드 클래스나 리시버를 알지 못함 |
+| 상호작용하는 객체 사이에서는 느슨한 결합을 사용한다 | 인보커는 커맨드 인터페이스만 알고, 커맨드는 리시버에게 작업을 위임. 세 객체가 느슨하게 연결됨 |
+| 클래스는 확장에 열려 있고 변경에 닫혀 있어야 한다 (OCP) | 새로운 가전제품/커맨드 추가 시 리모컨 코드 변경 없이 커맨드 클래스만 추가 |
+
+이 챕터에서 새로 등장하는 디자인 원칙은 없다.
+
+대신 지금까지 배운 원칙들(캡슐화, 느슨한 결합, OCP)이 커맨드 패턴에서 어떻게 종합적으로 적용되는지를 보여준다.
+
+---
+
+## 관련 패턴
+
+- **전략 패턴 (Strategy)**: 둘 다 행동을 객체로 캡슐화한다는 점에서 유사하다. 전략 패턴은 "어떻게 할지(알고리즘)"를 캡슐화하고, 커맨드 패턴은 "무엇을 할지(요청)"를 캡슐화한다. 전략은 대체가 목적이고, 커맨드는 분리/지연/기록이 목적이다.
+- **옵저버 패턴 (Observer)**: 옵저버 패턴의 알림 메커니즘에서 옵저버에게 전달되는 이벤트를 커맨드 객체로 만들면 두 패턴을 결합할 수 있다.
+- **메멘토 패턴 (Memento)**: 커맨드의 `undo()` 구현 시 이전 상태를 저장해야 하는 경우, 메멘토 패턴으로 상태를 스냅샷하여 저장하면 더 복잡한 Undo를 구현할 수 있다.
+- **컴포지트 패턴 (Composite)**: MacroCommand가 여러 커맨드를 담아 하나의 커맨드처럼 동작하는 구조는 컴포지트 패턴의 적용이다. 개별 커맨드와 매크로 커맨드를 동일한 인터페이스로 다룰 수 있다.