0

Suppose I have a class called 'Node' that has a method 'addChild'

@interface Node : NSObject

-(void) addChild:(Node *)n;

and I have a subclass called 'Sprite' that shouldn't respond to this method.

@interface Sprite : Node

I know I could do something like this:

@implementation Sprite

-(void) addChild:(Node *)n {
    NSLog(@"Don't call addChild on a Sprite!");
}

or

-(void) addChild:(Node *)n {
    NSAssert(NO, @"Don't call addChild on a Sprite!");
}

But is there a way to declare that the subclass doesn't respond to this method, and have the compiler throw an error? Getting a compiler error would be a lot better than a runtime error in this case.

EDIT

I realize this violates the Liskov substitution principle. But in Apple's documentation there's this:

"Any doesNotRecognizeSelector: messages are generally sent only by the runtime system. However, they can be used in program code to prevent a method from being inherited. For example, an NSObject subclass might renounce the copy or init method by re-implementing it to include a doesNotRecognizeSelector: message..."

I don't understand why throwing a runtime error rather than a compile-time error would be any less in violation of this principle.

4

4 回答 4

4

不。

OOP 中有一个称为Liskov 替换原则的原则,它指出您必须始终能够用子类的实例替换原始类的实例,而不会改变所讨论程序的所需行为。在您的情况下,您希望节点应该响应addChild:; 为了服从 LSP,我们必须让 SpriteaddChild:也做出响应。

这并不是说你无能为力。您可以让 Sprite 在发送给它们时抛出异常addChild:,或者让它们默默地忽略它,但我认为您真正想要的是 Node 和 Sprite 是同一父级的不同子类 - 我们称之为 AbstractNode。您会将大部分逻辑从 Node 移到 AbstractNode,然后addChild:在 Node 上实现。

于 2013-11-07T15:15:44.337 回答
0

我不确定编译时错误,但在运行时您可以尝试:

-(void)myMethod {
    [self doesNotRecognizeSelector:_cmd];
}

但是,我认为您需要重构这些类,以便有效地从父类中消除方法。否则,您似乎违反了继承。

于 2013-11-07T15:09:13.327 回答
-1

您可以使用一个类别来扩展该类并在该类别中实现您的 addChild 方法。

@interface Node(firstCategory)
-(void)addChild:(Node *)n;
@end

@implementation Node(firstCategory)
// your implementation of addChild
@end
于 2013-11-07T15:05:12.547 回答
-1

如果您只想让它响应超类(在本例中为“节点”)。只是不要在您的子类“Sprite”上实现它或在您的方法中手动调用它。如果你想做一些额外的事情。

@implementation Sprite

-(void) addChild:(Node *)n {
    [super addChild:n];
    // Do some other stuff 
}

如果您希望您的子类完全忽略该方法,您必须实现该方法并且什么都不做,但如果是这种情况,您就误解了继承范式。

@实现精灵

-(void) addChild:(Node *)n {
     // Ignore the method
}
于 2013-11-07T15:09:48.783 回答