Objective-C による実装

Objective-C による実装


Objective-C による実装例だ。

リクエストをメッセージとして実装してみた。これにより、リクエストを処理できるかどうかの判定に、メッセージ送信の利点を使えるんだ。



Handler クラス

/* チェインのための Handler クラス */
@interface Handler : NSObject
{
 /* 次のオブジェクト */
 id _successor;
}
/* 初期化メソッド */
- (id)initWithSuccessor:(id)successor;
/* リクエストを投げる */
- (void)sendRequest:(SEL)sel withObject:(id)obj;
@end

@implementation Handler

/* 初期化メソッド */
- (id)initWithSuccessor:(id)successor
{
 self = [super init];
 if (self) {
  _successor = successor;
 }
 return self;
}

/* リクエストを投げる */
/* リクエストはメッセージとして与えられる */
- (void) sendRequest:(SEL)sel withObject:(id)obj
{
 /* オブジェクトがメッセージを処理できるかどうかチェック */
 if ([self respondsToSelector:sel]) {
  /* メッセージ送信をすることで、ハンドラを呼び出す */
  [self performSelector:sel withObject:obj];
 }
 else {
  /* チェインをたぐって、*/
  /* 次のオブジェクトにリクエストを投げる */
  [_successor sendRequest:sel withObject:obj];
 }
}

@end

Button クラス

/* Button クラス */
@interface Button : Handler
{}
@end

@implementation Button


/* help リクエストのためのハンドラ */
- (void)help
{
 /* help リクエストの処理 */
}

@end

main()

int main(int argc, const char *argv[])
{
 /* それぞれのインスタンスを作る */
 Application* app;
 app = [[Application alloc] initWithSuccessor:nil];
 Dialog* dialog;
 dialog = [[Dialog alloc] initWithSuccessor:app];
 Button* button;
 button = [[Button alloc] initWithSuccessor:dialog];

 id arg;
 SEL sel;

 /* help リクエストを投げる */
 sel = NSSelectorFromString(@"help");
 [button sendRequest:sel withObject:arg];
 /* print リクエストを投げる */
 sel = NSSelectorFromString(@"print");
 [button sendRequest:sel withObject:arg];
 /* preview リクエストを投げる */
 sel = NSSelectorFromString(@"preview");
 [button sendRequest:sel withObject:arg];

 return 0;
}

こんな感じ。C++ とかと比べたときの利点としては、

・Handler クラスは、リクエストの種類を知る必要がない。リクエストの種類が増えても、Handler クラスを変更する必要がない。

・オブジェクトがリクエストに対するハンドラを実装しているかどうかを、メソッドの実装を調べることで実現できる。

・メッセージの種類が増えても、すべてのオブジェクトを変更する必要がない。ハンドラを実装するオブジェクトのみ変更すればよい。

といったことが上げられる。もちろん、Objective-C を使ったフレームワークである Cocoa (AppKit) には、responder chain が実装されていてアプリケーションで中心的な役割を果たしているので、得意技なわけだ。