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]();
Быстрый и грязный способ заключается в использовании
eval
, Но это настоятельно не рекомендуется по многим причинам - безопасность, производительность, удобочитаемость, поддерживаемостьfunction MyType() { } var typeName = 'MyType'; var typeObj = eval('new ' + typeName + '()');
Гораздо безопаснее и правильнее, чем
eval
использовать отображение имен строк на типы (спасибо @GaloisGecko)function createType(name) { var types = { "Square": Square, "Circle": Circle, "Triangle": Tringle }; return types.hasOwnProperty(name) ? new types[name]() : null; }
Наконец, лучшее и мудрое решение - применить шаблон Фабрики. Смотрите ответ @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();
Незначительным недостатком является то, что Эслинт жалуется (в некоторых настройках правила), что require
s должны быть размещены в верхней части модуля. И, конечно, требуется правильная обработка исключений с помощью try... catch и т. Д., Так что, вероятно, решение Factory лучше (поэтому я его приму), но я думаю, что для небольших специализированных случаев это решение подходит.