0

I have multiple classes deriving from one base class with a polymorphic method that accepts the enum type declared in the base class. I repeat the enum in the subclasses so that each subclass only accepts its own specific group of values:

class Character {

    enum Actions {

    }

    func performAction(action: Actions) {
        // Functions to be performed by all subclasses
    }
}


class Warrior: Character {

    enum Actions {
        case Attack, Block, Charge
    }

    override func performAction(action: Actions) {
        // Add subclass-specific behavior
    }
}

class Wizard: Character {

    enum Actions {
        case Attack, CastSpell, Run
    }

    override func performAction(action: Actions) {
        // Add subclass-specific behavior
    }
}

This of course doesn't work and I get

'Actions' is ambiguous for type lookup in this context.

I can't delete the enum in the base class because then I get an undeclared type error for the method. I have a strong feeling I'm going about this all wrong and trying to reinvent the wheel. Can someone point me in the right direction? Thank you.

3
  • Your aim being ease of configuration, exact compiler checks on availability (I.e. No runtime error for unsupported request type)? Commented Dec 28, 2015 at 14:21
  • @Wain My main goal is making sure each subclass's method only accepts what it's allowed to. Commented Dec 28, 2015 at 14:24
  • I went with the enum approach simply to define the parameter type allowed in the method Commented Dec 28, 2015 at 14:27

1 Answer 1

1

How about this approach:

enum Action {
    case Attack, Block, Charge, CastSpell, Run
}

class Character {

    final func performAction(action: Action) {
        if self.allowedActions().contains(action) {
            self.executeAction(action);
        }
    }

    func allowedActions() -> [Action] {
        // to be overriden in subclasses
        return []
    }

    func executeAction(action: Action) {
        // this will also be overriden in subclasses
    }
}

class Warrior: Character {
    override func allowedActions() -> [Action] {
        return [.Attack, .Block, .Charge]
    }

    override func executeAction(action: Action) {
        // do whatever is needed
    }
}

class Wizard: Character {
    override func allowedActions() -> [Action] {
        return [.Attack, .CastSpell, .Run]
    }

    override func executeAction(action: Action) {
        // do whatever is needed
    }
}

You use one enum to hold all possible actions, and you define per subclass which actions are allowed.

This way you can treat all characters the same: ask for the actions they can perform, so you can show a menu for example, and then ask the character to perform that action.

We can go even further, by using structs instead of classes and associated values for enums, this being a more swift-ish approach, but also a little bit more complicated to setup (but more logical).

Sign up to request clarification or add additional context in comments.

5 Comments

So, if I called the performAction() method, how would I check if the action is allowed? I would be checking if the array contains the requested action?
Yes, performAction() will need to check if the action is within the array of allowed one. I'll update the answer to reflect this.
@shades - I updated the answer, let me know if it clarifies things.
Thank you for the clarification. I will accept the answer. In your opinion, was this a good way for me to approach this problem from the outset?
Polymorphism is always good if you have a couple of entities that need to be handled the same in some situations, like yours. It will help you with modularisation and will keep your classes simple and short.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.