Objective-Cにおける”あり得ない”Visitorパターン実装
Visitorパターンてのがあります。
AcceptorをVisitorが渡り歩きますが、Acceptorもちょっと手助けする必要があります。
Acceptorを変更することなしに、Visitorを追加出来るという特徴があります。
Objective-Cにはカテゴリがありますので、Acceptorの手助けはカテゴリで追加することが出来てさらに便利です。
それでもAcceptorに色々追加するのは嫌なので、
@implementation NSObject(Acceptor) - (void)accept:(id)visitor { [visitor visit:self]; } @end
だけで終わらせたい。
しかし、Objective-Cにはオーバーロードがない。
そういう場合はAcceptorごとにメソッドを追加することになります。
@implementation ClassA (Acceptor) - (void)accept:(id)visitor { [visitor visitClassA:self]; } @end @implementation ClassB (Acceptor) - (void)accept:(id)visitor { [visitor visitClassB:self]; } @end
美しくありません!
それに、Visitorパターンの特徴は
Acceptorを変更することなしに、Visitorを追加出来る
であったはずです。これでは魅力半減です。*1
で、編み出したのがこれ。
@implementation NSObject(Acceptor) - (void)accept:(id)visitor { [visitor visit:self]; } @end @implementation NSObject(Visitor) - (void)visit:(id)acceptor { NSString *className = NSStringFromClass([acceptor class]); NSString *selName = [NSString stringWithFormat:@"visit%@:", className]; SEL selector = NSSelectorFromString(selName); return [self performSelector:selector withObject:acceptor]; } @end @implementation Visitor - (void)visitClassA:(id)acceptor { // do something. } - (void)visitClassB:(id)acceptor { // do something. } @end
すばらしい!
AcceptorはシンプルなままAcceptorごとに違ったメソッドが呼ばれてる!
Visitor側には多数のメソッドが必要ですが、これはオーバーロードを使っても同じこと。
完璧である!
クラスクラスタのことを考えなければ(w
あと速度。
*1:主観が大いに混ざっています。本来の特徴はそこではありません。