简体   繁体   中英

Objective C Subclassing: Is this proper?

So I'm working on an iPad game using the cocos2d framework.

My game requires different buildings to be spawned at the beginning of a "level". The user gets to choose which buildings they want to use.

An important functionality here is that different buildings will perform different actions when pressed.

I have a parent class that looks something like this:

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;

So most of my buildings are very similar. Each building has their own initBuilding method which overrides the parent. The initBuilding method calls the super initWithName method which then looks up a plist with information about that building (sprite name, etc).

Each building also has their own onBuildingPressed method, which also overrides the parent method. This is very important functionality.

The part that I'm having trouble with:

I want to spawn the buildings based on what the player selects. What I'm currently doing is something like this:

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;

Since BuildingX, BuildingY, BuildingZ are all subclasses of BaseBuilding, initBuilding does call the correct method.

Later on I can call [rightBuilding onBuildingPressed]; and it works as expected.

BuildingX has a removeAmmo method that the other buildings don't have, so I have to do this to call it: [(BuildingX*)centerBuilding removeAmmo] .

Is this proper, or this a better way of doing this?

The only thing that I notice is that, if you have many subclasses - provided that all subclasses have some alphabetical order - you do it faster and more elegantly by getting a class object according to the value of choice:

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

But this is just a matter of style and rapidity (writing the code, I mean). Your method is perfectly fine and there's nothing wrong with it.

You can verify the class at run time to guarantee there's no room for error here like so:

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

Seems logical to me. I don't know if it's stylish, the snobs can determine that for you. If it works, it works. I don't see the point in fixing things that aren't broken.

Yes, it's correct. But:

1) If you are casting all your subclasses to the parent class, and you need to use a particular method of your subclass, then it's useless casting to the right subclass ONLY in certain circumstances. Try to make the removeAmmo a base method...

or

2) make your building subclass calling the removeAmmo method from its inside, and declare the removeAmmo method in a category

From an external point of view, the BaseClass has not the removeAmmo method, so it's not logic to declare a public method which could be called only re-casting your object to a specific subclass.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM