web-dev-qa-db-fra.com

Quelle est l'intention des modules Ninject?

Je suis un débutant complet pour ninject

J'ai séparé le code de quelqu'un d'autre et j'ai trouvé plusieurs instances de modules nInject - des classes qui dérivent de Ninject.Modules.Module et qui ont une méthode de chargement qui contient la plupart de leur code.

Ces classes sont appelées en appelant la méthode LoadModule d'une instance de StandardKernel et en lui passant une instance de la classe module.

Peut-être que je manque quelque chose d'évident ici, mais quel est l'avantage de cela sur la simple création d'une ancienne classe simple et l'appel de sa méthode, ou peut-être une classe statique avec une méthode statique?

58
Jonathan

Les modules Ninject sont les outils utilisés pour enregistrer les différents types avec le conteneur IoC. L'avantage est que ces modules sont ensuite conservés dans leurs propres classes. Cela vous permet de mettre différents niveaux/services dans leurs propres modules.

// some method early in your app's life cycle
public Kernel BuildKernel()
{
    var modules = new INinjectModule[] 
    {
        new LinqToSqlDataContextModule(), // just my L2S binding
        new WebModule(),
        new EventRegistrationModule()
    };
    return new StandardKernel(modules);
}

// in LinqToSqlDataContextModule.cs
public class LinqToSqlDataContextModule : NinjectModule
{
    public override void Load()
    {
        Bind<IRepository>().To<LinqToSqlRepository>();
    }
}

Le fait d'avoir plusieurs modules permet de séparer les préoccupations, même au sein de votre conteneur IoC.

Le reste d'entre vous interroge sonne comme s'il s'agissait davantage d'IoC et de DI dans son ensemble, et pas seulement de Ninject. Oui, vous pouvez utiliser des objets de configuration statiques pour faire à peu près tout ce qu'un conteneur IoC fait. Les conteneurs IoC deviennent vraiment sympas lorsque vous avez plusieurs hiérarchies de dépendances.

public interface IInterfaceA {}
public interface IInterfaceB {}
public interface IInterfaceC {}

public class ClassA : IInterfaceA {}

public class ClassB : IInterfaceB
{
    public ClassB(IInterfaceA a){}
}

public class ClassC : IInterfaceC
{
    public ClassC(IInterfaceB b){}
}

La construction de ClassC est difficile à ce stade, avec plusieurs profondeurs d'interfaces. Il est beaucoup plus facile de simplement demander au noyau un IInterfaceC.

var newc = ApplicationScope.Kernel.Get<IInterfaceC>();
61
Jarrett Meyer

Peut-être que je manque quelque chose d'évident ici, mais quel est l'avantage de cela sur la simple création d'une ancienne classe simple et l'appel de sa méthode, ou peut-être une classe statique avec une méthode statique?

Oui, vous pouvez simplement appeler un groupe d'instructions Bind<X>().To<Z>() pour configurer les liaisons, sans module.

La différence est que si vous mettez ces instructions dans un module, alors:

  • IKernel.Load(IEnumerable<Assembly>) peut découvrir dynamiquement de tels modules par réflexion et les charger.
  • les liaisons sont logiquement regroupées sous un nom; vous pouvez utiliser ce nom pour les décharger à nouveau avec IKernel.Unload(string)
9
Wim Coenen

Peut-être que je manque quelque chose d'évident ici, mais quel est l'avantage de cela sur la simple création d'une ancienne classe simple et l'appel de sa méthode, ou peut-être une classe statique avec une méthode statique?

Pour nous, c'est la possibilité d'ajouter très facilement des tests ultérieurement. Remplacez simplement quelques liaisons avec des mockobjects et le tour est joué ..... sur le code hérité sans DI qui câblait "tout", il est presque impossible de commencer à insérer des cas de test sans retravailler. Avec une DI en place ET tant qu'elle a été utilisée correctement là où la DI a tout câblé, il est très simple de le faire même sur du code hérité qui peut être très moche.

Dans de nombreux frameworks DI, vous pouvez utiliser le module de production pour votre test avec un module de test qui remplace les liaisons spécifiques avec les mockobjects (en laissant le reste du câblage en place). Il peut s'agir de tests système plus que de tests unitaires, mais j'ai tendance à préférer des tests de niveau supérieur au développeur moyen car il teste l'intégration entre les classes et c'est une excellente documentation pour quelqu'un qui rejoint le projet et peut voir l'ensemble de la fonctionnalité en action (à la place de quelques parties de la fonction) sans avoir à configurer un système entier).

3
Dean Hiller