web-dev-qa-db-ja.com

Node.js-変数で指定されたクラス名のオブジェクトを作成します

私は次のようなクラス階層を持っています:

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

ここで、ストラテジーパターンを実装し、文字列に格納されるクラスのオブジェクトを作成したいと思います。 PHP私は使用します:

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

Node.jsに同等のものはありますか?

7
Forseti

より堅牢でテスト可能なアプローチを採用したい場合は、クラスとファクトリパターンの組み合わせを使用してオブジェクトを発行できます。以下を確認してください。この設定では、より詳細なロジックと将来のテストを含めると、より簡単になり、柔軟性が向上することがわかります。また、.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 -列挙型アプローチのデモ

5
scniro

安全な方法は、ファクトリオブジェクトを定義することです。

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]();
7
GaloisGecko

よく検討すると、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();
_

マイナーな欠点は、eslintが(一部のルール設定では)requiresをモジュールの上に配置する必要があると文句を言うことです。そしてもちろん、try ... catchなどによる適切な例外処理が必要なので、おそらくファクトリソリューションの方が優れています(それを受け入れるつもりです)が、小さな特殊なケースではこのソリューションで問題ないと思います。

2
Forseti
  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 answer を参照してください。また、あなたは良い説明と例を見つけることができます ここ

2
oxfn