Node.js - создать объект с именем класса, указанным в переменной

У меня есть иерархия классов, как:

               |-> Square
AbstractShape -+-> Circle
               |-> Triangle

Теперь я хотел бы реализовать шаблон стратегии и создать объект класса, который хранится в строке. В PHP я бы использовал:

$type = 'Square';
$obj = new $type();

Есть ли эквивалент в Node.js?

4 ответа

Решение

Если вы хотите использовать более надежный и проверяемый подход, вы можете использовать комбинацию классов и шаблон фабрики для выдачи объекта. Проверьте следующее, вы увидите, что с этой настройкой, включающей более детальную логику и тестирование в будущем, станет проще и даст вам большую гибкость. Вы также абстрагируете себя от нового объекта, находящегося за .issue звонок - который может быть выгодным и удобным в некоторых случаях.

Я также заметил, что вы упомянули свой фон PHP, поэтому я также демонстрирую, как в ES6 можно использовать объектно-ориентированный подход.

class AbstractShape {
  constructor(type) {
    this.type = type;
  }

  getType() {
    console.log(`I am a ${this.type}`);
  }
}

class Square extends AbstractShape {
  constructor(type) {
    super(type);
    this.sides = 4;
  }

  getDescription() {
    console.log(`I have ${this.sides} equal sides`);
  }
}

class ShapeFactory {
  static issue(type) {
    switch(type) {
      case 'Square': return new Square(type);
        break;
      case 'Circle': /* same pattern with a Circle class */
        break;
    }
  }
}

let shape = ShapeFactory.issue('Square');

shape.getType();        /* I am a Square */
shape.getDescription(); /* I have 4 equal sides */

JSFiddle Link - демо


Кроме того, если вы хотите что-то более отказоустойчивое, чем работа с избыточными строками, например 'Square' - есть несколько творческих способов использовать перечислимые подходы, которые могли бы уточнить это еще дальше. Я сохраню здесь недвижимость и не буду повторно хешировать фрагмент кода, но включу в себя скрипку, которую вы должны проверить.

JSFiddle Link - демонстрация подхода enum

Безопасным способом было бы определение фабричного объекта:

function Square() {
}

// here other constructors for Circle and Triangle   

var factory = {
    "Square": Square,
    "Circle": Circle,
    "Triangle" : Triangle   
}

var typeName;

// here some code which sets typeName

var typeObj = new factory[typeName]();
  1. Быстрый и грязный способ заключается в использовании eval, Но это настоятельно не рекомендуется по многим причинам - безопасность, производительность, удобочитаемость, поддерживаемость

    function MyType() {
    }
    
    var typeName = 'MyType';
    var typeObj = eval('new ' + typeName + '()');
    
  2. Гораздо безопаснее и правильнее, чем eval использовать отображение имен строк на типы (спасибо @GaloisGecko)

    function createType(name) {
      var types = {
        "Square": Square,
        "Circle": Circle,
        "Triangle": Tringle
      };
      return types.hasOwnProperty(name) ? new types[name]() : null;
    }
    
  3. Наконец, лучшее и мудрое решение - применить шаблон Фабрики. Смотрите ответ @scniro. Также вы можете найти хорошее описание и пример здесь

При ближайшем рассмотрении для Node.js. существует довольно простой способ. Когда вы создаете экземпляр объекта самым простым способом, вы на самом деле пишете new <variableName> где variableName это тело некоторой функции или класса, определенное и экспортированное в некотором модуле. Чтобы назначить эту функцию / класс переменной вы require() Это.

Итак, вместо

const type = 'Square';
const aSquare = new type();

вам нужно написать:

const type = 'Square';
const shape = require(`${pathToShapeModules}/${type}.js`); 
const aShape = new shape();

Незначительным недостатком является то, что Эслинт жалуется (в некоторых настройках правила), что requires должны быть размещены в верхней части модуля. И, конечно, требуется правильная обработка исключений с помощью try... catch и т. Д., Так что, вероятно, решение Factory лучше (поэтому я его приму), но я думаю, что для небольших специализированных случаев это решение подходит.

Другие вопросы по тегам