web-dev-qa-db-ja.com

RequireJSによる依存性注入

アプリに依存関係注入を提供するために、どのくらいRequireJSを拡張できますか?例として、シングルトンになりたいモデルがあるとします。自己強制getInstance()タイプのシングルトンのシングルトンではなく、コンテキスト強制シングルトン(「コンテキスト」ごとに1つのインスタンス)。次のようなことをしたい...

require(['mymodel'], function(mymodel) {
   ...
}

そして、mymodelをMyModelクラスのインスタンスにします。複数のモジュールでこれを行う場合、mymodelを同じ共有インスタンスにする必要があります。

Mymodelモジュールを次のようにすることで、この作業を成功させました。

define(function() {
    var MyModel = function() {
        this.value = 10;
    }
    return new MyModel();
});

このタイプの使用は予想され、一般的ですか、それともRequireJSを悪用していますか? RequireJSで依存性注入を実行するより適切な方法はありますか?ご協力いただきありがとうございます。まだこれを把握しようとしています。

35
Aaronius

これは実際には依存関係の注入ではなく、代わりにサービスの場所です。他のモジュールは文字列「キー」によって「クラス」を要求し、「サービスロケータ」(この場合はRequireJS)が接続されているインスタンスを取得しますそれらを提供します。

依存関係の注入には、MyModelコンストラクター、つまりreturn MyModelを返し、次に中央の構成ルートMyModelのインスタンスを他のインスタンスに注入します。これがどのように機能するかのサンプルをここにまとめました: https://Gist.github.com/1274607(以下も引用)

このようにして、コンポジションルートは、MyModelの単一のインスタンス(つまり、それをシングルトンスコープにする)を渡すか、それを必要とする各クラス(インスタンススコープ)に新しいインスタンスを渡すか、またはその間に何かを渡すかを決定します。そのロジックは、MyModelの定義にも、そのインスタンスを要求するクラスにも属していません。

(補足:私はまだ使用していませんが、 wire.js はJavaScriptの本格的な依存関係注入コンテナーであり、非常にクールに見えます。)


RequireJSを実際に使用することで必ずしもRequireJSを悪用しているわけではありません。なぜ次のことをしないのですか?

define(function () {
    var value = 10;

    return {
        doStuff: function () {
            alert(value);
        }
    };
});

あなたが見逃しているかもしれない類推は、関数と値を付加できる名前空間であるにもかかわらず、モジュールが他のほとんどの言語の「名前空間」と同等であるということです。 (つまり、PythonよりもJavaまたはC#のようになります。)これらはクラスと同等ではありませんが、モジュールのエクスポートをそれらに等しくすることはできます。特定のクラスインスタンスの。

したがって、モジュールに関数と値を直接アタッチすることでシングルトンを作成できますが、これは静的クラスを使用してシングルトンを作成するようなものです。柔軟性が低く、一般にベストプラクティスではありません。ただし、依存関係注入のためにシステムを適切に設計するには、JavaScriptの標準ではないことを最初からよく考える必要があるため、ほとんどの人はモジュールを「静的クラス」として扱います。


これが https://Gist.github.com/1274607 インラインです:

// EntryPoint.js
define(function () {
    return function EntryPoint(model1, model2) {
        // stuff
    };
});

// Model1.js
define(function () {
    return function Model1() {
        // stuff
    };
});

// Model2.js
define(function () {
    return function Model2(helper) {
        // stuff
    };
});

// Helper.js
define(function () {
    return function Helper() {
        // stuff
    };
});

// composition root, probably your main module
define(function (require) {
    var EntryPoint = require("./EntryPoint");
    var Model1 = require("./Model1");
    var Model2 = require("./Model2");
    var Helper = require("./Helper");

    var entryPoint = new EntryPoint(new Model1(), new Model2(new Helper()));
    entryPoint.start();
});
60
Domenic

DI/IOCに真剣に取り組んでいる場合は、wire.jsに興味があるかもしれません: https://github.com/cujojs/wire

サービスの再配置(Domenicの説明のようですが、RequireJSの代わりにcurl.jsを使用)とDI(wire.jsを使用)を組み合わせて使用​​します。テストハーネスでモックオブジェクトを使用する場合、サービスの再配置は非常に便利です。他のほとんどのユースケースでは、DIが最良の選択のようです。

3
unscriptable

自己強制getInstance()タイプのシングルトンのシングルトンではなく、コンテキスト強制シングルトン(「コンテキスト」ごとに1つのインスタンス)。

静的オブジェクトにのみお勧めします。 require/defineブロックでロードするモジュールとして静的オブジェクトを持つことは完全に問題ありません。次に、静的プロパティと関数のみを含むクラスを作成します。次に、PI、E、SQRTなどの定数と、round()、random()、max()、min()などの関数を持つMath Objectに相当するものを取得します。いつでも注入できるユーティリティクラスの作成に最適です。

これの代わりに:

define(function() {
    var MyModel = function() {
        this.value = 10;
    }
    return new MyModel();
});

これはインスタンスを作成し、静的オブジェクトのパターンを使用します(値が常にオブジェクトと同じであるものはインスタンス化されません):

define(function() {
    return {
       value: 10
    };
});

または

define(function() {
    var CONSTANT = 10;
    return {
       value: CONSTANT
    };
});

インスタンス(new MyModel();を返すモジュールを使用した結果)を渡す場合は、初期化関数内で、現在の状態/コンテキストをキャプチャする変数を渡すか、情報を含むオブジェクトを渡しますモジュールが認識する必要がある状態/コンテキスト。

1
widged