How can I refactor the switch case to call methods from a class?

Viewed 250

I have a Hero class that extends the Player class, this hero can perform various actions, most of these actions are overridden from the Player class, so far so good.

class Hero extends Player {
  constructor(level = 1) {
    super();
    this.level = level;
  }

  // override
  attack() {
    return 'attacking';
  }

  defend() {
    return 'defending';
  }

  walk() {
    return 'walking';
  }

  run() {
    return 'running';
  }

  fly() {
    return 'flying';
  }

  jump() {
    return 'jumping';
  }
}

module.exports = Hero

Now I need to call these actions dynamically by sending a parameter, for example, I look for a user in the database and check what the action's type is (integer), if it's 0, execute the attack() method, if it's 1, executes the defend() method. I created a switch case with all possible cases, however whenever I add a new action, I will have to modify the switch and it gets bigger and bigger. How best to work with this? Knowing that I have to call these methods dynamically with a "type" parameter.

const hero = new Hero();
let type = 1; // this type is dynamic and comes from a database API
let result = null;
switch (type) {
    case 0:
        result = hero.attack();
        break;

    case 1:
        result = hero.defend();
        break;

    case 2:
        result = hero.walk();
        break;

    case 3:
        result = hero.run();
        break;

    case 4:
        result = hero.fly();
        break;

    case 5:
        result = hero.jump();
        break;
}

console.log(result)
3 Answers

You can map numbers to functions using an object, which will make it become way smaller (one line each). Here's a simplified example:

let actions = {
    1: attack,
    2: defend,
};

actions[type]();

In case your action types are really defined as successive integers starting from 0 then you may just use an array instead of a map;

var actions = [attack, defend, walk, ...],
    type    = 0;
actions[type](); // "attacking"

Instead of naming the functions as attack or fly. you can name the function as type which you expecting from the db. In the existing context it was integer so I have implemented using integers.

class Hero {
  constructor(level = 1) {
    this.level = level;
  }

  1() {
    return 'attacking';
  }

  2() {
    return 'defending';
  }

  3() {
    return 'walking';
  }

  4() {
    return 'running';
  }

  5() {
    return 'flying';
  }

  jumping() {
    return 'jumping';
  }
}

const hero = new Hero();
let type = 1; // this type is dynamic and comes from a database API
let result = eval('hero[' + type + ']()');

console.log(result)

type = 'jumping' // this type is dynamic and comes from a database API
result = eval('hero.' + type + '()');

console.log(result)

let result = eval('hero[' + type + ']()'); and i have generated the function name and evaluated it's value dynamically. these are some of the resources which might help you double dispatch and dynamic-function-names

Related