0

假设我有一个用户不应该实例化的伪抽象基类。基本上,当他们尝试在类上调用 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,因为这是用户首先尝试调用的方法。

4

2 回答 2

3

我也研究过如何有效地抽象类的问题,但我并不喜欢这个解决方案。在我看来,它会让你的子类代码看起来很奇怪,而且对于普通的观察者来说更难阅读。

如果您要求您的子类在 中进行特定的初始化-init,那么您的可能是唯一的解决方案。但是,如果您只想确保它们具有子类,则可以在以下范围内执行此操作-init

-(id) init
{
    NSAssert(![self isMemberOfClass:[KTPhysicsShape class]], 
                                         @"KTPhysicsShape must be subclassed!");
    return [super init];
}
于 2013-04-05T15:25:11.353 回答
2

这表明您的架构存在严重缺陷。指定初始化器链的全部意义在于它可以以可预测的顺序执行而不会发生变化。向子类添加合同义务以遵循正常链会增加脆弱性和不必要的复杂性。

缺陷的症结在于你有一个看起来不是真正抽象的抽象类。它可以有具体的实例,这需要具体的初始化。

首先,为什么不能将类分解为真正的抽象类和具体类?

如果你不能(或不想——当然,更多的类有它自己的成本),那么一种解决方案是将常用的初始化操作分解为一个单独的方法:

- (void) commonKTPhysicsShapeInit
{
    ....
}

那不叫super 这不会在您的标题中声明;它是一种仅限内部实现的方法,因此得名。

然后,让您的子类通过调用commonInit. 对于该类的具体实例,有一个单独的初始化器,它既调用commonInit又执行具体的初始化舞蹈。

它与您提出的类似,但以更接近现有模式的方式呈现界面。

于 2013-04-05T15:51:22.243 回答