【发布时间】:2012-03-31 09:51:44
【问题描述】:
假设我在classA 上拥有A 属性,在classB 上拥有B 属性,我希望classAB 拥有A 和B 这两个属性。我仍然不明白如何使这一切与 composition 一起工作。
我意识到这可以通过继承来完成,但我想学习如何通过 composition 来做到这一点。我查看了示例,但仍然不明白它是如何工作的。
【问题讨论】:
标签: objective-c ios composition
假设我在classA 上拥有A 属性,在classB 上拥有B 属性,我希望classAB 拥有A 和B 这两个属性。我仍然不明白如何使这一切与 composition 一起工作。
我意识到这可以通过继承来完成,但我想学习如何通过 composition 来做到这一点。我查看了示例,但仍然不明白它是如何工作的。
【问题讨论】:
标签: objective-c ios composition
您创建了一个新类,其中有 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 中可以做的一件事是捕获发送到您的对象但没有关联方法的消息,并将它们转发给另一个对象。如果您正在编写一个将伪装成另一个类的类,或者如果有许多不同的消息要转发并且您不想手动将它们全部写出来,则此技巧很有用。
使用消息转发的缺点是您放弃了一些控制权,并且很难预测您的班级或转发班级何时处理消息。例如,如果一个超类实现了一个方法,则该方法将被执行,并且不会调用转发代码。
【讨论】:
NSString(这是一个类集群和子类化它不是微不足道的)我想要一个边带的通信。运行时的关联对象是考虑的主要替代方法,但我觉得 forwardingTargetForSelector:(尽管在我的情况下创建一个假装的子类而不是组合)是更清洁和更易读的解决方案。
假设 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;
}
【讨论】:
ab 转换为类型ClassA,那么对于所有定义的方法,它的行为就像ClassA 的真实实例一样和属性,如果您将其转换为ClassB,它对于所有未由ClassA 定义的方法和属性的行为都会相同?
ClassAB 实现了ClassA 也可以执行的选择器,那么@Tommy 实际上是不正确的,在这种情况下将调用ClassAB 实现(例如,自定义-description 实现)。
ab 完全正确,如您的示例所示。