オブジェクトCを使用したココアの「テンプレートメソッドパターン」とは何ですか? (言語比較思考)
質問
ここは テンプレートメソッドパターン 、JavaとC ++は、仮想関数で簡単に実装できます。このパターンを実装するオブジェクトCはどうですか? Cocoa Touch(iOS)の例はありますか?
解決
として エル すでに指摘している、すべてのObjective-Cメソッドは本質的に仮想です。これは、他のCのような言語とはまったくメッシュしない言語の特徴です。そうは言っても、テンプレートメソッドパターンの基本は、「手動で」サブクラスに特定の機能を実装することにより、Objective-Cでまだ達成できます。たとえば(リンクされたWikipediaの記事のコンベンションを使用):
@interface Game
{
int playersCount;
}
- (void)playOneGame:(int)numPlayers;
// "virtual" methods:
- (void)initializeGame;
- (void)makePlay:(int)player;
- (BOOL)endOfGame;
- (void)printWinner;
@end
@implementation Game
- (void)initializeGame { NSAssert(FALSE); }
- (void)makePlay:(int player) { NSAssert(FALSE); }
- (BOOL)endOfGame { NSAssert(FALSE); return 0; }
- (void)printWinner { NSAssert(FALSE); }
- (void)playOneGame:(int)numPlayers
{
//..
}
@end
上記のコードは、のサブクラスを強制します Game
ベースクラスの実装の1つが呼び出された瞬間に例外をスローすることにより、「仮想」メソッドをオーバーライドする。実際、これにより、テストはコンパイラステージ(C ++またはJavaのように)からランタイム段階(Objective-Cで同様のことが行われることが多い)に移動します。
もし、あんたが 本当 サブクラスがオーバーライドすることが許可されていないというルールを実施したい playOneGame:
方法、(*)を試みて、内部から正しい実装を確認できます init
方法:
@implementation Game
...
- (void)init
{
if ((self = [super init]) == nil) { return nil; }
IMP my_imp = [Game instanceMethodForSelector:@selector(playOneGame:)];
IMP imp = [[self class] instanceMethodForSelector:@selector(playOneGame:)];
NSAssert(imp == my_imp);
return self;
}
...
@end
(*)このコードは、再実装するサブクラスに対する100%の堅実な防御をもたらさないことに注意してください playOneGame:
, 、Objective-Cの本質はサブクラスをオーバーライドすることを可能にするので instanceMethodForSelector:
正しい結果を生成するため。
他のヒント
Objective-Cでは、すべての方法はC ++に似ています virtual
方法。
Objective-Cテンプレートでは、アルゴリズムのスケルトンを持っているが、さまざまな方法で実装できる場合に使用されます。テンプレートメソッドは、アルゴリズムを実行する手順を定義し、すべてまたは一部のサブクラスに共通する可能性のあるデフォルトの実装を提供できます。
例を見てみましょうが、最初に写真を見てください
@interface Worker : NSObject
- (void) doDailyRoutine;
- (void) doWork; // Abstract
- (void) comeBackHome;
- (void) getsomeSleep;
@end
@implementation Worker
- (void) doDailyRoutine {
[self doWork];
[self comeBackHome];
[self getsomeSleep];
}
- (void) doWork { [self doesNotRecognizeSelector:_cmd]; }
- (void) comeBackHome { [self doesNotRecognizeSelector:_cmd]; }
- (void) getsomeSleep { [self doesNotRecognizeSelector:_cmd]; }
// [self doesNotRecognizeSelector:_cmd] it will force to call the subclass Implementation
@end
@interface Plumber : Worker
@end
@implementation Plumber
- (void) doWork { NSLog(@“Plumber Work"); }
@end
@interface Electrician : Worker
@end
@implementation Electrician
- (void) doWork { NSLog(@“Electrician Work"); }
@end
@interface Cleaner : Worker
@end
@implementation Cleaner
- (void) doWork { NSLog(@“Cleaner Work"); }
@end
この例では、Dowork()はすべてのサブクラスによって実装される必要がある抽象関数であり、このパターンはココアフレームワークで主に使用されています。
「テンプレートメソッドパターン」を理解するのに役立つことを願っています。