2017-05-23 5 views
1

TypescriptとNodeJSではかなり新しく、実行時にオブジェクトを作成するためにファクトリを使用しようとしています。Typescript/NodeJS - ファクトリを使用しているときの循環依存性

import {BaseContainer} from "../Containers/BaseContainer"; 
import {TextContainer} from "../Containers/TextContainer"; 
/** 
* Used to dynamically create objects with different container classes 
* in runtime 
*/ 
export class ContainerFactory { 

    // Object containing all class names and types 
    private dictionary: Object; 

    /** 
    * Initializes factory dictionary 
    */ 
    constructor() { 
     // Initialize dictionary with classes 
     this.dictionary = { 
      "default": BaseContainer, 
      "Text": TextContainer, 
      "TextContainer": TextContainer 
     } 
    } 

    /** 
    * Builds object depending on className 
    * @param className 
    * @param params 
    */ 
    build(className: string, params: Object) { 
     // Return new class of type className, if not found 
     // return object with class of set default class 
     return className in this.dictionary ? new this.dictionary[className](params) : new this.dictionary['default']; 

    } 
} 

{ 
type: "Text", 
name: "Title" 
} 

私の工場は、次のようになります。例として

、次のオブジェクトは、実行時に、私はTextContainerのインスタンスを作成したいとなって、プロパティの型のテキストを持っています

BaseContainerクラス(TextContainerで拡張され、このファクトリに存在するより多くのクラスによって拡張される)に問題が発生します。関数でファクトリを使用します。ここで循環依存が発生します。これは、BaseContainer私はContainerFactをインポートするoryとContainerFactory BaseContainerにインポートされます。

私は木のような階層構造を持ち、コンテナにはコンテナである子があるため、BaseContainerにはファクトリが必要です。

この問題を回避する方法や、コードを確実に機能させるためにコードを屈折させる方法については、お勧めします。 同様の問題を検索しましたが、まだ回避策が見つかりませんでした。

IはTextContainerクラス(BaseContainerを拡張)に次のエラーを受け取る:このタスクの

extendStatics(d, b); 
     ^

TypeError: Object prototype may only be an Object or null: undefined 
+0

BaseContainerクラスのファクトリを別のクラスにする必要がある処理関数で問題を修正し、そこで処理を実行します。この方法では、ファイルはファクトリのみをインポートします。誰かがより洗練されたソリューションを持っているなら、私はそれを答えとしてマークします。 – Stefan

答えて

1

よりよい解決策は、それぞれのコンストラクタ関数にタイプ名をマッピングするためにデコレータを使用することであろう。たとえば、次のように

Decorator.ts:

export function Container(className: string) 
{ 
    return (target: any) => 
    { 
     Meta.classNameToCtor[!!className ? className : target.name] = target; 
    }; 
} 

Meta.ts:

@Container("default") 
export class BaseContainer {...} 

export class Meta 
{ 
    public static classNameToCtor: {[key: string]: any} = {}; 
} 

今あなたがする必要があるすべては、このようなあなたのコンテナクラスのそれぞれを飾るあります

工場出荷時には、Meta

build(className: string, params: Object) 
{ 
    return className in Meta.classNameToCtor ? new Meta.classNameToCtor[className](params) : new Meta.classNameToCtor['default']; 
} 

このアプローチでは、インポートの依存関係が完全になくなり、スケーラビリティが向上します。

+0

ありがとうございますが、小さな問題があります。私はあなたがMeta.classNameToCtorのinseadのMeta.typesを意味したと思います。とにかく、それは問題ではありません。私の問題は、それが動作するbasecontainerクラスでは、それが型に追加されますが、そのベースコンテナを継承するクラスでは、そのクラスを型に追加することはできません。拡張クラスに@Container( 'Text')を必ず追加しました。 – Stefan

+0

オススメして申し訳ありません。デコレータが起動しない理由は、対応するモジュールがまだロードされていないことが原因です。たとえば、TextContainerが別々のTextContainer.tsで宣言されている場合、最初に "読み込まれている"ことを確認する必要があります。すべてのデコレータが起動され、Metaにはすべての型が含まれます。 – Amid

+0

申し訳ありません、ありがとうございます。今は動作し、Server.tsにロードします。 Importsのような別個のファイルを作成する方が良いと思いますか?tsとそこにすべてのインポートを呼び出すと、混乱を減らすためにServer.tsファイルでImport.tsのインポートを呼び出しますか?いずれにせよ、私は答えとしてあなたの応答をマークしています。再度、感謝します。 – Stefan