假设A
上的classA
属性B
上有属性classB
,我希望classAB
同时拥有属性A
和B
{{1}}。我仍然不明白如何使用组合来完成所有工作。
我意识到这可以通过继承完成,但我想学习如何使用 composition 来完成此操作。我看了一些例子,但我仍然不知道它是如何运作的。
答案 0 :(得分:21)
创建一个新类,它具有classA和classB的实例作为成员变量。然后通过传递get / set方法来实现属性。
@interface ClassAB
{
ClassA *objectA;
ClassB *objectB;
}
@property (nonatomic,strong) id propertyA;
@property (nonatomic,strong) id propertyB;
@end
@implementation ClassAB
- (id)propertyA { return objectA.propertyA; }
- (void)setPropertyA:(id)value { objectA.propertyA = value; }
- (id)propertyB { return objectB.propertyB; }
- (void)setPropertyB:(id)value { objectB.propertyB = value; }
@end
这就是组成。有些语言有特殊的语法来执行此操作(例如,在Ruby中,您可以在一个类/模块中包含一组方法),但Objective-C不允许这样做。
您可以在Objective-C中执行的一件事是捕获发送到您的对象的消息,这些消息没有关联的方法,并将它们转发给另一个对象。如果您正在编写一个将作为另一个类构成的类,或者如果要转发许多不同的消息并且您不想手动将它们全部写出来,这个技巧很有用。
使用邮件转发的缺点是您放弃了某些控制,并且在您的类或转发类处理邮件时,可能更难预测。例如,如果超类实现了一个方法,那么将执行该方法,并且不会调用转发代码。
答案 1 :(得分:8)
假设ClassA
和ClassB
已按照您的说法实施,这非常有效,并且可以轻松扩展。
@interface ClassAB : NSObject
@property int a;
@property int b;
@property ClassA *aObject;
@property ClassB *bObject;
@end
@implementation ClassAB
@dynamic a, b;
@synthesize aObject, bObject;
-(id) forwardingTargetForSelector:(SEL)aSelector
{
if ([aObject respondsToSelector:aSelector])
return aObject;
else if ([bObject respondsToSelector:aSelector])
return bObject;
return nil;
}
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
ClassA *a = [ClassA new];
ClassB *b = [ClassB new];
ClassAB *ab = [ClassAB new];
ab.aObject = a;
ab.bObject = b;
ab.a = 10;
ab.b = 20;
NSLog(@"%i, %i", a.a, b.b); // outputs 10, 20
}
return 0;
}