代码之家  ›  专栏  ›  技术社区  ›  CodeSmile Paul Beusterien

是否在允许[super-init]的情况下阻止调用ObjC“抽象”类的init方法?

  •  0
  • CodeSmile Paul Beusterien  · 技术社区  · 12 年前

    假设我有一个用户不应该实例化的伪抽象基类。基本上,当他们试图在类上调用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 因为这是用户最喜欢的称呼。

    2 回复  |  直到 12 年前
        1
  •  3
  •   CodeSmile Paul Beusterien    12 年前

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

    如果您需要子类在中进行特定的初始化 -init ,你的可能是唯一的解决方案。但如果你只是想确保 子类化,您可以在 -初始化 :

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

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

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

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

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

    - (void) commonKTPhysicsShapeInit
    {
        ....
    }
    

    这不算什么 super . 这不会在您的标头中声明;它是一个仅实现的内部方法,因此得名。

    然后,让您的子类通过标准指定的初始化器进行调用 commonInit 。对于该类的具体实例,有一个单独的初始值设定项,两个都调用 通用初始化 并进行具体的初始化舞蹈。

    它与您提出的类似,但以更紧密地遵循现有模式的方式呈现界面。