4

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)
Vinicius Aquino
  • 697
  • 13
  • 27

3 Answers3

3

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]();
Hugo Mota
  • 11,200
  • 9
  • 42
  • 60
1

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"
Redu
  • 25,060
  • 6
  • 56
  • 76
0

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

rohanraj
  • 392
  • 2
  • 12
  • It is definitely the alternative that shortens the lines, but it is not readable by the programmer an unnamed method :( – Vinicius Aquino Jun 19 '21 at 14:18
  • In the context of readability, you can update the values in the DB which is the more readable function name. @viniciussvl – rohanraj Jun 19 '21 at 14:22
  • if i could change the type in the database, would i return the function name instead of returning the integer type? – Vinicius Aquino Jun 19 '21 at 14:27
  • yes, returning the function name would be a better idea it will give you more readability. I have updated my answer for your reference. @viniciussvl – rohanraj Jun 19 '21 at 14:37