Прямой языковой поддержки нет, но вы можете сделать что-то подобное с пересылкой сообщений. Допустим, у вас есть трейт-классы «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];
(Изменить: добавлена обработка ошибок.)
person
Sherm Pendley
schedule
08.04.2011