假设我有一个用户不应该实例化的伪抽象基类。基本上我想在他们尝试在类上调用init时抛出警告,或者返回一个具有默认值的具体实例。
但是,该基类的具体实现必须在其初始化程序中调用[super init]
。当然应该允许这样做。
我最好怎么做?
我在想这应该没问题:
@implementation KTPhysicsShape
-(id) init
{
// throw exception here or return concrete instance with default values
}
// this is what subclasses would call in place of [super init]:
-(id) internal_initFromSubclass
{
return [super init];
}
@end
对此方法有何顾虑?我知道其他人仍然可以调用内部方法,但我最关心的是禁止使用init
,因为这是用户最想要调用的内容。
答案 0 :(得分:3)
我还研究过如何有效地抽象类的问题,但我不是那个解决方案。在我看来,这将使您的子类代码看起来很奇怪,而且对于不经意的观察者来说更难阅读。
如果您要求子类在-init
中进行特定初始化,那么您的子类可能是唯一的解决方案。但是,如果您只是想确保他们 子类化,那么您可以在-init
内完成:
-(id) init
{
NSAssert(![self isMemberOfClass:[KTPhysicsShape class]],
@"KTPhysicsShape must be subclassed!");
return [super init];
}
答案 1 :(得分:2)
这表明您的架构存在严重缺陷。指定初始化链的整个要点是它可以以可预测的顺序执行而不会有变化。将合同义务添加到 not 的子类遵循正常链增加了脆弱性和不必要的复杂性。
缺陷的关键在于你有一个看起来并不真正抽象的抽象类;它可以具有具体实例,并且需要具体初始化。
首先,为什么不能将类分解为真正的抽象类和具体的类?
如果你不能(或者不想 - 当然,更多的类本身有成本),那么一种解决方案是将常用的初始化操作分解为单独的方法:
- (void) commonKTPhysicsShapeInit
{
....
}
不会调用super
。这不会在您的标头中声明;它是一个内部到实现的方法,因此名称。
然后,让您的子类通过调用commonInit
的标准指定初始化程序进行调用。对于该类的具体实例,有一个单独的初始化程序,它都调用commonInit
并进行具体的初始化舞蹈。
它与您提出的类似,但以更紧密地遵循现有模式的方式呈现界面。