在子类中向下转换Objective-C实例变量
我有一个类在子类中向下转换Objective-C实例变量,objective-c,class,properties,protocols,subclass,Objective C,Class,Properties,Protocols,Subclass,我有一个类a,其实例变量类型为X @interface A : NSObject { X *x; } @end 一些X实例还符合协议p。我想专门为那些X实例实现一个专门版本的a @interface B : A { X <P> *x; } @end 如果重写实例变量,我必须将更改传播到超类A。这需要额外的功能 使用属性而不是实例变量:这会奏效吗?可以在子类中重新定义属性吗 @interface A : NSObject { X *x; } @proper
a
,其实例变量类型为X
@interface A : NSObject {
X *x;
}
@end
一些X
实例还符合协议p
。我想专门为那些X
实例实现一个专门版本的a
@interface B : A {
X <P> *x;
}
@end
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
@接口A:NSObject{
X*X;
}
@性质(强,非原子)X*X;
@结束
@实施A
-(X*)X
{
返回x;
}
-(无效)setX:(X*)anX
{
x=anX;
}
@结束
@接口B:A
@性质(强,非原子)X*X;
@结束
@实施B
@结束
- 最简单的解决方案是隐藏实例变量。您可以通过将IVAR从接口移动到实现文件中的类延续来实现这一点:
@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;
}
-(X*)XTHAT协议
{
X*X=super.X;
返回([x:协议])?x:无;
}
然而,这种方法会破坏多态性
老实说,我想你应该用另一种方法来解决这个问题。子类化似乎不是一种自然的选择。最简单的解决方案是隐藏实例变量。您可以通过将IVAR从接口移动到实现文件中的类延续来实现这一点:
@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;
}
-(X*)XTHAT协议
{
X*X=super.X;
返回([x:协议])?x:无;
}
然而,这种方法会破坏多态性
老实说,我想你应该用另一种方法来解决这个问题。子类化似乎不是一种自然的适合。您试图做的事情违反了面向对象编程的一个基本原则,即。B的实例可以传递给任何需要A的代码,并且该代码有权将其视为A。这意味着允许它在对象上调用
-setX:
,传递X的实例,而不要求该对象符合协议P
换句话说,您试图创建一个不是a的a的子类
您想要这样做的事实表明存在设计混乱。你应该后退一步,重新思考。首先,仅根据接口设计所有类,并确保其接口在继承方面有意义。只有考虑到实现。 您试图做的违背了面向对象编程的基本原则。B的实例可以传递给任何需要A的代码,并且该代码有权将其视为A。这意味着允许它在对象上调用
-setX:
,传递X的实例,而不要求该对象符合协议P
换句话说,您试图创建一个不是a的a的子类
您想要这样做的事实表明存在设计混乱。你应该后退一步,重新思考。首先,仅根据接口设计所有类,并确保其接口在继承方面有意义。只有考虑实现。 YEP,但是
-x
方法公开,因为属性在公共头中是只读的。-setX:
的子类实现“以完全不同的方式对待它”正是我所指出的违反LSP的行为。上面的代码片段不会使属性为只读。这没什么区别。子类的约束比其超类的约束窄是没有意义的。子类应该是超类型,具有更广泛的可能操作范围。也许您应该解释真正的类和协议应该是什么,以及为什么要这样做。我怀疑您误用了协议的概念。是的,但是-setX:
的子类实现可能与基类中的不同,并且可能会以完全不同的方式对待它。另外,在我的例子中,只有-x
方法公开,因为属性在公共头中是只读的。-setX:
的子类实现“以完全不同的方式对待它”正是我所指出的违反LSP的行为。上面的代码片段不会使属性为只读。这没什么区别。子类的约束比其超类的约束窄是没有意义的。子类应该是超类型,具有更广泛的可能操作范围。也许您应该解释真正的类和协议应该是什么,以及为什么要这样做。我怀疑你误用了协议的概念。