我有一个类A
,其实例变量类型为X
。
@interface A : NSObject {
X *x;
}
@end
某些X
个实例另外符合协议P
。我想专门为那些A
实例实现X
的专用版本。
@interface B : A {
X <P> *x;
}
@end
编译好。但是,当我从x
实例访问B
时,更改不会传播到A
。因此,未重新定义的A
函数使用的是除X
函数之外的B
个实例。
在仅添加协议时,是否有可能重新定义实例变量? 关于子类有类似的question。但是,子类和协议不一样。虽然我的方法编译得很好,但它不能按预期工作。
如果不可能:是否有共同的模式来执行此操作?
如果我没有用新类型覆盖实例变量,那么代码就会变得杂乱无章:
[((X <P> *)x) methodOfP]
如果我覆盖实例变量,我必须自己将更改传播到超类A
。这需要额外的功能。
使用属性而不是实例变量:这甚至可以解决吗?可以在子类中重新定义属性吗?
@interface A : NSObject {
X *x;
}
@property (strong, nonatomic) X *x;
@end
@implementation A
- (X *)x
{
return x;
}
- (void)setX:(X *)anX
{
x = anX;
}
@end
@interface B : A
@property (strong, nonatomic) X <P> *x;
@end
@implementation B
@end
答案 0 :(得分:1)
您尝试做的事情违反了面向对象编程的基本原则Liskov Substitution Principle。可以将B的实例传递给任何期望A的代码,并且该代码有权将其视为A.这意味着允许在对象上调用-setX:
,传入X 的实例而不任何要求该对象符合协议P 。
换句话说,您正在尝试创建A的子类,而不是A。
您想要这样做的事实表明设计混乱。你应该退一步重新思考。首先,仅根据接口设计所有类,并确保它们的接口在继承方面有意义。只有这样才能考虑实施。
答案 1 :(得分:0)
最简单的解决方案是隐藏实例变量。您可以通过将ivars从接口移动到实现文件中的类继续来完成此操作:
@interface A ()
{
X *x;
}
@end
或执行的负责人:
@implementation A
{
X *x;
}
//methods go here
@end
您不应直接访问超类ivar。而是使用super.propertyName
。然后,您可以向子类添加一个方法,只有在它实现协议时才返回x
:
-(X*<protocol>)xThatImplementProtocol
{
X *x = super.x;
return ([x conformsToProtocol:protocol]) ? x : nil;
}
然而,这种方法会破坏多态性。
说实话,我认为你会使用不同的方法,可能是合成,来解决这个问题。子类化似乎不太合适。