コマンドパターン
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 94/110。
Commandパターンは、リクエストをオブジェクトとしてカプセル化することで、異なるリクエストによるクライアントのパラメータ化、操作のキューイング、または「元に戻す」機能のサポートを可能にします。メソッドを直接呼び出す代わりに、アクションをコマンドオブジェクトにラップし、それを保存したり、受け渡したり、後で実行したりできるようにします。
このパターンは、3つの主要なコンポーネントで構成されています。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 はライトについて何も知りません。与えられたコマンドを実行するだけです。この疎結合により、インボーカー(起動側)を修正することなく、新しいコマンドを簡単に追加できるようになります。Command パターンは、アクションを第一級オブジェクトとして扱う必要がある、元に戻す/やり直し(undo/redo)システム、タスクキュー、またはマクロ記録の実装に最適です。
チャレンジ
簡単Command パターンを使用して、テキストエディタのコマンドシステムを構築しましょう!テキスト操作をコマンドオブジェクトとしてカプセル化するシステムを作成します。これにより、エディタは各操作の詳細を知ることなく、さまざまなアクションを実行できるようになります。これは Command パターンの典型的なユースケースです。各アクションがオブジェクトとして保存される、元に戻す/やり直し(undo/redo)システムのようなものだと考えてください。
コードを 2 つのファイルに整理します。
commands.dart: ここにコマンドシステムを作成します。まず、execute()メソッドを宣言する抽象クラスCommandから始めます。次に、String contentフィールド(初期状態は空)を持ち、以下の 3 つのメソッドを持つTextDocumentクラス(レシーバ)を作成します。append(String text)- content の末尾にテキストを追加しますclear()- content を空の文字列に設定しますshow()-Document: [content]を出力します
TextDocumentを操作する 3 つの具体的なコマンドを実装します。AppendCommand- コンストラクタでドキュメントとテキストを受け取り、実行時にテキストを追加しますClearCommand- コンストラクタでドキュメントを受け取り、実行時に内容をクリアしますShowCommand- コンストラクタでドキュメントを受け取り、実行時にその内容を表示します
TextEditorクラス(インボーカー)を作成します。コマンドをキューに追加するためのaddCommand(Command command)メソッドと、キューに入れられたすべてのコマンドを順番に実行するrunAll()メソッドを持つ必要があります。main.dart: コマンドファイルをインポートし、Command パターンを実演します。TextDocumentとTextEditorを作成します。次のコマンドを順番にキューに追加します:Helloを追加、Worldを追加、ドキュメントを表示、!を追加、再度表示、ドキュメントをクリア、そして最後に一度表示します。その後、キューに入れられたすべてのコマンドを実行します。
TextEditor が追加、クリア、表示について何も知らないことに注目してください。与えられたコマンドを実行するだけです。この疎結合こそが 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: キューに入れられたすべてのコマンドを実行する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ