web-dev-qa-db-fra.com

Injection de dépendance avec des exigences

Combien puis-je étirer des exigences pour fournir une injection de dépendance pour mon application? À titre d'exemple, disons que j'ai un modèle que je veux être un singleton. Pas un singleton dans une getinstance autonome () - Type Singleton, mais un singleton exécutif contextuel (une instance par "contexte"). Je voudrais faire quelque chose comme ...

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

Et avoir mymodel être une instance de la classe MyModel. Si je devais le faire dans plusieurs modules, je voudrais que MyModel soit la même instance partagée.

J'ai réussi à faire ce travail en faisant le module MyModel comme celui-ci:

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

Ce type d'usage est-il attendu et commun ou je abuse des exigences? Y a-t-il un moyen plus approprié que je puisse effectuer une injection de dépendance avec des exigences? Merci de votre aide. Essayant toujours de saisir cela.

35
Aaronius

Ce n'est pas réellement une injection de dépendance, mais plutôt une localisation de service: vos autres modules Demander une "classe" par une chaîne "clé" et récupérez une instance de celui-ci que le "localisateur de service" (dans ce cas requis) a été câblé à prévoyez-leur.

L'injection de dépendance impliquerait de renvoyer le constructeur MyModel, c'est-à-dire return MyModel, Puis dans une racine centrale Composition root injecter une instance de MyModel dans d'autres instances . J'ai mis ensemble un échantillon de la façon dont cela fonctionne ici: https://gist.github.com/1274607 (également cité ci-dessous)

De cette façon, la racine de la composition détermine s'il faut distribuer une seule instance de MyModel (c'est-à-dire que le singleton scoped) ou neufs pour chaque classe qui le nécessite (instance Scoped) ou quelque chose entre les deux. Cette logique n'appartient ni dans la définition de MyModel, ni dans les classes qui lui demandent une instance.

(Note latérale: Bien que je ne l'ai pas utilisé, Wire.js est un conteneur d'injection de dépendance à part entière pour JavaScript qui a l'air assez cool.)


Vous n'utilisez pas nécessairement les exigences en l'utilisant comme vous le faites, bien que ce que vous faites semble un peu rond-point, c'est-à-dire la déclaration d'une classe que de le renvoyer d'une nouvelle instance. Pourquoi ne pas simplement faire ce qui suit?

define(function () {
    var value = 10;

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

L'analogie que vous serez peut-être manquante est que les modules équivalent à des "espaces de noms" dans la plupart des autres langues, mais vous pouvez attacher des fonctions et des valeurs à. (Donc, plus comme Python que Java ou C #.) Ils ne sont pas équivalents aux classes, bien que comme vous l'avez montrée, vous pouvez rendre les exportations de module égales à celles d'une instance de classe donnée.

Vous pouvez donc créer des singletons en attachant directement des fonctions et des valeurs directement sur le module, mais c'est une sorte de création d'un singleton à l'aide d'une classe statique: elle est très inflexible et généralement pas la meilleure pratique. Cependant, la plupart des gens traitent leurs modules comme des "classes statiques", car l'architecture correcte d'un système d'injection de dépendance nécessite beaucoup de réflexion dès le départ qui n'est pas vraiment la norme en JavaScript.


Voici https://gist.github.com/1274607 Inline:

// 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

Si vous êtes sérieux sur DI/IOC, vous pourriez être intéressé par Wire.js: https://github.com/cujojs/wire

Nous utilisons une combinaison de relocalisation des services (comme Domenic décrit, mais à l'aide de curl.js au lieu d'exigerjs) et de di (utilisant Wire.Js). La déménagement de service est très pratique lorsque vous utilisez des objets simulés dans des harnais de test. DI semble le meilleur choix pour la plupart des autres cas d'utilisation.

3
unscriptable

Pas un singleton dans une getinstance autonome () - Type Singleton, mais un singleton exécutif contextuel (une instance par "contexte").

Je le recommanderais seulement pour des objets statiques. Il est parfaitement amende d'avoir un objet statique en tant que module que vous chargez d'utiliser dans les blocs requis/définir. Vous créez ensuite une classe avec uniquement des propriétés et des fonctions statiques. Vous avez alors l'équivalent de l'objet mathématique qui a des constantes comme PI, E, SQRT et des fonctions telles que rondes (), aléatoires (), max (), min (). Idéal pour créer des classes utilitaires pouvant être injectées à tout moment.

Au lieu de cela:

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

Ce qui crée une instance, utilisez le modèle d'un objet statique (une des valeurs où les valeurs sont toujours identiques que l'objet ne devient jamais instancié):

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

ou

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

Si vous souhaitez passer une instance (le résultat de l'utilisation d'un module qui renvoie de nouveau myModel ();), dans une fonction d'initialisation, passez une variable qui capture l'état/le contexte actuel ou transmettez-le sur l'objet contenant des informations sur État/contexte que vos modules doivent connaître.

1
widged