커맨드 패턴
Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 94번째.
커맨드 패턴(Command pattern)은 요청을 객체로 캡슐화하여, 클라이언트를 서로 다른 요청으로 매개변수화하거나, 작업을 큐에 저장하거나, 실행 취소 기능을 지원할 수 있게 합니다. 메서드를 직접 호출하는 대신, 액션을 저장, 전달 또는 나중에 실행할 수 있는 커맨드 객체 안에 감쌉니다.
이 패턴은 세 가지 핵심 구성 요소로 이루어집니다: execute 메서드를 가진 Command 인터페이스, 특정 작업을 구현하는 Concrete Commands, 그리고 실제 작업을 수행하는 Receiver입니다. 선택 사항인 Invoker는 명령이 무엇을 하는지 알지 못한 채 명령을 트리거합니다:
abstract class Command {
void execute();
}
class Light {
void turnOn() => print('Light is ON');
void turnOff() => print('Light is OFF');
}
class TurnOnCommand implements Command {
final Light light;
TurnOnCommand(this.light);
@override
void execute() => light.turnOn();
}
class TurnOffCommand implements Command {
final Light light;
TurnOffCommand(this.light);
@override
void execute() => light.turnOff();
}
class RemoteControl {
Command? _command;
void setCommand(Command command) {
_command = command;
}
void pressButton() {
_command?.execute();
}
}
void main() {
var light = Light();
var remote = RemoteControl();
remote.setCommand(TurnOnCommand(light));
remote.pressButton(); // Light is ON
remote.setCommand(TurnOffCommand(light));
remote.pressButton(); // Light is OFF
}RemoteControl은 조명에 대해 아무것도 알지 못합니다. 그저 주어진 명령이 무엇이든 실행할 뿐입니다. 이러한 디커플링(decoupling) 덕분에 인보커(invoker)를 수정하지 않고도 새로운 명령을 쉽게 추가할 수 있습니다. 커맨드 패턴은 작업을 일급 객체로 취급해야 하는 실행 취소/다시 실행 시스템, 작업 큐 또는 매크로 기록을 구현하는 데 이상적입니다.
챌린지
쉬움Command 패턴을 사용하여 텍스트 에디터 명령 시스템을 만들어 봅시다! 텍스트 작업을 명령 객체로 캡슐화하는 시스템을 만들게 됩니다. 이를 통해 에디터는 각 작업의 세부 사항을 알지 못해도 다양한 동작을 실행할 수 있습니다. 이것은 Command 패턴의 전형적인 사용 사례입니다. 각 동작이 객체로 저장되는 실행 취소/다시 실행 시스템처럼 생각하면 됩니다.
코드를 두 개의 파일로 구성합니다:
commands.dart: 여기에서 명령 시스템을 만듭니다.execute()메서드를 선언하는 추상 클래스Command부터 시작하세요. 그런 다음String content필드(처음에는 비어 있음)를 가지고 세 가지 메서드를 갖는TextDocument클래스(수신자)를 만듭니다:append(String text)- content 끝에 텍스트를 추가합니다.clear()- content를 빈 문자열로 설정합니다.show()-Document: [content]를 출력합니다.
TextDocument와 함께 작동하는 세 가지 구체적인 명령을 구현합니다:AppendCommand- 생성자에서 문서와 텍스트를 받고, 실행될 때 텍스트를 추가합니다.ClearCommand- 생성자에서 문서를 받고, 실행될 때 문서를 지웁니다.ShowCommand- 생성자에서 문서를 받고, 실행될 때 그 내용을 보여줍니다.
TextEditor클래스(호출자)를 만듭니다. 명령을 대기열에 추가하는addCommand(Command command)메서드와 대기열에 있는 모든 명령을 순서대로 실행하는runAll()메서드가 있어야 합니다.main.dart: 명령 파일을 가져와서 Command 패턴을 시연합니다.TextDocument와TextEditor를 생성합니다. 다음 명령을 순서대로 대기열에 추가합니다:Hello추가,World추가, 문서 표시,!추가, 다시 표시, 문서 지우기, 마지막으로 한 번 더 표시. 그런 다음 대기열에 있는 모든 명령을 실행합니다.
TextEditor가 추가, 지우기 또는 표시에 대해 아무것도 모른다는 점에 주목하세요. 단지 주어진 명령을 실행할 뿐입니다. 이러한 결합 해제(decoupling)가 Command 패턴의 핵심입니다!
예상 출력:
Document: Hello World
Document: Hello World!
Document: 직접 해보기
import 'commands.dart';
void main() {
// TODO: TextDocument 인스턴스 생성
// TODO: TextEditor 인스턴스 생성
// TODO: 다음 명령들을 순서대로 큐에 추가:
// 1. "Hello" 추가
// 2. " World" 추가
// 3. 문서 표시
// 4. "!" 추가
// 5. 문서를 다시 표시
// 6. 문서 내용 지우기
// 7. 문서를 마지막으로 한 번 더 표시
// TODO: 대기열의 모든 명령 실행
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.