【问题标题】:Prevent ObjC "abstract" class' init method from being called while allowing [super init]?防止在允许 [super init] 的同时调用 ObjC“抽象”类的 init 方法?
【发布时间】:2023-04-06 10:09:01
【问题描述】:

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

对这种方法有任何顾虑吗?我知道其他人仍然可以调用 internal 方法,但我最关心的是禁止init,因为这是用户最想调用的方法。

【问题讨论】:

  • 看起来还不错。但是如果你在init 中调用internal_initFromSubclass 而不是抛出异常怎么办。这样,类中只有你的方法可以初始化对象..

标签: objective-c properties protected ivar


【解决方案1】:

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

如果您要求您的子类在-init 中进行特定的初始化,您的可能是唯一的解决方案。但是,如果您只是想确保它们具有子类化,您可以在-init 中做到这一点:

-(id) init
{
    NSAssert(![self isMemberOfClass:[KTPhysicsShape class]], 
                                         @"KTPhysicsShape must be subclassed!");
    return [super init];
}

【讨论】:

  • 我想你想要isMemberOfClass:
  • 谢谢,迈克。在我看来,这是“不是-isKindOfClass: 的方法”。
  • @SeamusCampbell 不应该自我分配吗?
  • 这里不需要,因为除了返回它之外,我们没有对[super init] 返回的对象做任何事情。
  • 很好的解决方案!我最初考虑过这一点,但因为我认为代码会像往常一样在 self = [super init] 之后运行,所以我放弃了它。我的方法也没有像 bburn 描述的那样古怪(我也不喜欢)。
【解决方案2】:

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

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

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

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

- (void) commonKTPhysicsShapeInit
{
    ....
}

这不会调用super 这不会在您的标题中声明;它是一个内部实现的方法,因此得名。

然后,让您的子类通过调用commonInit 的标准指定初始化程序进行调用。对于该类的具体实例,有一个单独的初始化程序,它既调用commonInit 又执行具体的初始化程序。

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

【讨论】:

  • 完全同意不破坏初始化链……我问的原因之一
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
  • 2012-03-21
  • 1970-01-01
  • 2011-03-04
  • 2012-03-26
相关资源
最近更新 更多