Objective C Subclassing:这是正确的吗?

时间:2013-08-17 17:03:31

标签: objective-c inheritance cocos2d-iphone polymorphism

所以我正在使用cocos2d框架开发iPad游戏。

我的游戏需要在“关卡”的开头生成不同的建筑物。用户可以选择他们想要使用的建筑物。

这里的一个重要功能是不同的建筑物在按下时会执行不同的操作。

我有一个看起来像这样的父类:

BaseBuilding.h

@interface BaseBuilding : NSObject {
    CGRect _hitBox;
    NSString *_name;

    CCSprite *_sprite;
    int _identifier;
    int _health;

    int _coolDownDuration;
}

@property (atomic, retain) CCSprite *sprite;
@property (atomic, assign) int identifier;
@property (atomic, assign) int health;

- (void) onBuildingPressed;
- (id) initWithName:(NSString*)baseName;
- (id) initBuilding;
- (CGRect) hitBox;
- (void) sustainDamage;

所以我的大多数建筑都非常相似。每个建筑物都有自己的initBuilding方法,该方法会覆盖父级。 initBuilding方法调用super initWithName方法,然后查找plist,其中包含有关该构建的信息(精灵名称等)。

每个建筑物也有自己的onBuildingPressed方法,该方法也会覆盖父方法。这是非常重要的功能。

我遇到问题的部分:

我想根据玩家选择的内容生成建筑物。我目前正在做的是这样的事情:

BaseBuilding *building;

switch (choice) {
    case 1:
        building = [BuildingX alloc];
        [building initBuilding];
        break;
    case 2:
        building = [BuildingY alloc];
        [building initBuilding];
        break;
    case 3:
        building = [BuildingZ alloc];
        [building initBuilding];
        break;
}

return building;

由于BuildingX,BuildingY,BuildingZ都是BaseBuilding的子类,initBuilding确实调用了正确的方法。

稍后我可以致电[rightBuilding onBuildingPressed];,它按预期工作。

BuildingX有一个其他建筑没有的removeAmmo方法,所以我必须这样做才能调用它:[(BuildingX*)centerBuilding removeAmmo]

这是正确的,还是更好的方法呢?

4 个答案:

答案 0 :(得分:1)

我唯一注意到的是,如果你有许多子类 - 只要所有子类都有一些字母顺序 - 你可以通过根据选择的值获取一个类对象来更快更优雅地完成它:

NSString* className= [NSString stringWithFormat: @"Building%c",'X'-1+choice];
Class class= NSClassFromString(className);
BaseBuilding* building= [[class alloc] initBuilding];

但这只是风格和速度问题(编写代码,我的意思)。你的方法非常好,并没有任何问题。

答案 1 :(得分:1)

您可以在运行时验证课程,以确保此处没有错误的余地:

if ( [centerBuilding respondsToSelector:NSSelectorFromString(@"removeAmmo")] ) {
    [centerBuilding performSelector:NSSelectorFromString(@"removeAmmo"];
}

答案 2 :(得分:0)

对我来说似乎很合乎逻辑。我不知道它是否时尚,势利的人可以为你决定。如果它工作,它的工作原理。我没有看到修复没有破坏的东西的重点。

答案 3 :(得分:0)

是的,这是对的。 但是:

1)如果要将所有子类强制转换为父类,并且需要使用子类的特定方法,那么仅在某些情况下才会将其强制转换为正确的子类。尝试将removeAmmo作为基本方法......

2)使你的构建子类从其内部调用removeAmmo方法,并在类别中声明removeAmmo方法

从外部角度来看,BaseClass没有removeAmmo方法,因此声明一个只能将对象重新转换为特定子类的公共方法并不是逻辑。