今回からはCommandパターンを取り上げる。この辺りから、Cocoaとの比較が俄然面白くなってくる。とりあえず、GoF本におけるCommandパターンの説明から始めよう。
Commandパターンとは
Commandパターンは、名前の通りコマンドを表すパターンだ。この「コマンド」は、広い意味ではあるオブジェクトに対する「要求」ということだが、正味な話、グラフィックユーザインタフェースにおけるコマンドのことと理解してしまっていいだろう。つまり、メニューを選択したり、ボタンを押したりして、アプリケーションに命令を送るコマンドのことだ。
このコマンドをクラスを使って表してやろう、というのがCommandパターンだ。例えば、コピーを行うためのCopyCommandクラス、ペーストを行うためのPasteCommandクラスを作成する。
そして、GoF本のCommandパターンの特徴は、それぞれのCommandクラスが、コマンドの「実行」も行う事だ。そのために、CommandクラスにExecuteという関数がついている。このExecute関数の中で、コピーやペーストといった処理を行おう、というものになる。
このCommandパターンを使うと、グラフィカルユーザインタフェースでの処理の流れは次のようになる。まず、ユーザがメニューの選択や、ボタンのクリックを行う。すると、それぞれのメニューやボタンに応じて、CopyCommandクラスやPasteCommandクラスのインスタンスを作る。そして、Execute関数を呼び出して、コマンドを実行する。
このようにして、コマンドの呼び出し元と、コマンドの実行を分離するのがCommandパターンの狙いだ。
Commandパターンの登場人物
Commandパターンの登場人物は、大きく分けると3つになる。まず、コマンドを作成して呼び出すInvoker。コマンドそのものを表すCommand。そして、コマンドの実行対象となるReceiverだ。
具体的に説明すると、Invokerはユーザが操作するメニューやボタン、Commandはコピーやペーストを表すものになる。そして、新たに登場したReceiverだが、これはCommandのExecute関数の中で、実際に操作される対象になる。
例えば、コピーコマンドを考えよう。ドキュメントを扱っているアプリケーションならば、ドキュメントの中で選択されている項目をクリップボードにコピーすることになる。そこで、CopyCommandのExecuteでは、ドキュメントを表す Documentクラスに対して、選択している項目のコピーを命じることになる。このDocumentクラスが、コマンドの実行の対象という事で、Receiverになる。
また、ドキュメントを開くコマンドも考えてみよう。これを、OpenCommandというクラスで表す。ドキュメントを開くというコマンドは、まずDocumentクラスに関連する。そして、開いたドキュメントはアプリケーション全体で管理する必要があるだろう。そこで、Applicationクラスを登場させる。OpenCommandでは、DocumentクラスとApplicationクラスとがReceiverになるだろう。
このように、CommandパターンのExecute関数を実現するには、あらかじめReceiverを設定しておかないといけない。
Commandパターンの実装
では、このようなGoFスタイルのCommandパターンを、Objective-Cで実装してみよう。
ここでは、Invokerの役割はClientが行うものとする。Commandとして、OpenCommandとPasteCommandを用意する。そしてReceiverには、先に紹介したようなApplicationとDocumentを使おう。
これらの関連は、次の図のようになる。
![]() |
なかなか大掛かりになってきた。Commandのクラスからは、Receiverのクラスへの参照があるところに注目してほしい。これは、最終的なコマンドの実行はApplicationやDocumentといったReceiverのクラスで行われるためだ。
では、これをObjective-Cで実装してみよう。
まず、ApplicationとDocumentを、次のように定義する。
List 1.
@interface Application : NSObject
{
NSMutableArray* _documents;
}
- (void)addDocument:(Document*)document;
@end
@interface Document : NSObject
- (void)open;
- (void)paste;
@end
Applicationは、インスタンス変数としてDocumentの配列を保持する。そのために、addDocument:というメソッドを提供する。Documentの方では、openとpasteというメソッドをそれぞれ用意した。
次にCommand側だ。ルートクラスとしてCommandクラスを用意する。
List 2.
@interface Command : NSObject
- (void)execute;
@end
このクラスには、executeメソッドを用意する。ここで、コマンドの実行を行う訳だ。
これで準備が整った。中心となるOpenCommand、PasteCommandクラスを実装してみよう。まず、OpenCommandだ。
List 3.
@interface OpenCommand : Command
{
Application* _application;
}
- (id)initWithApplication:(Application*)application;
@end
@implementation OpenCommand
- (id)initWithApplication:(Application*)application
{
self = [super init];
if (!self) return nil;
_application = application;
return self;
}
- (void)execute
{
Document* document;
document = [[Document alloc] init];
[_application addDocument:document];
[document open];
}
@end
OpenCommandは、Applicationクラスへの参照が必要になる。そこで、初期化メソッドでその参照を渡してやる。
executeメソッドでは、まずDocumentクラスのインスタンスを作る。そして、それをApplicationに登録して、openメソッドを呼んでやればいい。
次は、PasteCommandだ。
List 4.
@interface PasteCommand : Command
{
Document* _document;
}
- (id)initWithDocument:(Document*)document;
@end
@implementation PasteCommand
- (id)initWithDocument:(Document*)document
{
self = [super init];
if (!self) return nil;
_document = document;
return self;
}
- (void)execute
{
[_document paste];
}
@end
PasteCommandには、Documentの参照が必要だ。これも初期化メソッドで渡している。そうしておけば、executeメソッドではDocumentのpasteを呼ぶだけだ。
これが、GoFスタイルでのCommandということになる。次回は、現役のアプリケーションフレームワークであるCocoaでは、どのようにコマンドを処理しているのか紹介しよう。
提供:毎日キャリアバン ク
毎日キャリアバンクではITエンジニア出身のキャリアコンサルタントで形成する IT専門のチームを編成し、キャリアに応じた専任コンサルタントがご相談を承り ます。キャリアチェンジから市場価値の可能性、ご収入などの相談から面接のア ドバイスまでお気軽にご相談ください。求人情報誌や転職情報サイトなどで一般 に公開されていないような「急募求人案件」も随時ご紹介が可能です。まずはご 登録ください!