Прямой языковой поддержки нет, но вы можете добиться чего-то похожего с пересылкой сообщений.Допустим, у вас есть классы признаков "Foo" и "Bar", которые определяют методы "-doFoo
" и "-doBar
" соответственно.Вы можете определить свой класс, чтобы иметь черты, например:
@interface MyClassWithTraits : NSObject {
NSMutableArray *traits;
}
@property (retain) NSMutableArray* traits;
-(void) addTrait:(NSObject*)traitObject;
@end
@implementation MyClassWithTraits
@synthesize traits;
-(id)init {
if (self = [super init]) {
self.traits = [NSMutableArray array];
}
return self;
}
-(void) addTrait:(NSObject*)traitObject {
[self.traits addObject:traitObject];
}
/* Here's the meat - we can use message forwarding to re-send any messages
that are unknown to MyClassWithTraits, if one of its trait objects does
respond to it.
*/
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector {
// If this is a selector we handle ourself, let super handle this
if ([self respondsToSelector:aSelector])
return [super methodSignatureForSelector:aSelector];
// Look for a trait that handles it
else
for (NSObject *trait in self.traits)
if ([trait respondsToSelector:aSelector])
return [trait methodSignatureForSelector:aSelector];
// Nothing was found
return nil;
}
-(void) forwardInvocation:(NSInvocation*)anInvocation {
for (NSObject *trait in self.traits) {
if ([trait respondsToSelector:[anInvocation selector]]) {
[anInvocation invokeWithTarget:trait];
return;
}
}
// Nothing was found, so throw an exception
[self doesNotRecognizeSelector:[anInvocation selector]];
}
@end
Теперь вы можете создавать экземпляры MyClassWithTraits и добавлять любые объекты «черты», которые вам нравятся:
MyClassWithTraits *widget = [[MyClassWithTraits alloc] init];
[widget addTrait:[[[Foo alloc] init] autorelease]];
[widget addTrait:[[[Bar alloc] init] autorelease]];
Вы можете сделать эти вызовы для -addTrait:
в методе -init
MyClassWithTraits, если вы хотите, чтобы у каждого экземпляра этого класса были одинаковые черты.Или вы можете сделать это так, как я это сделал здесь, что позволяет назначать разные наборы характеристик для каждого экземпляра.
И затем вы можете вызывать -doFoo
и -doBar
, как если бы они были реализованыс помощью виджета, даже если сообщения пересылаются одному из его объектов признаков:
[widget doFoo];
[widget doBar];
( Редактировать : добавлена обработка ошибок.)