2016-11-03 1 views
0

J'ai rencontré ce que je crois devoir être un problème commun lié à l'injection de dépendance. J'ai du mal à trouver des exemples pertinents et je n'aime pas la meilleure solution que j'ai trouvée.Comment configurer ninject pour injecter différents types de dépendances dans la même classe?

public class WasherDryerFolderSystem : ILaundrySystem 
{ 
    private IWasher _washer; 
    private IDryer _dryer; 
    private IFolder _folder; 

    public WasherDryerFolderSystem(IWasher washer, IDryer dryer, IFolder folder) 
    {...} 

    public void DoLaundry() 
    { 
     _washer.Wash(); 
     _dryer.Dry(); 
     _folder.Fold(); 
    } 
} 


public class HandWasher : IWasher {...} 
public class MachineWasher : IWasher {...} 

public class HandDryer : IDryer {...} 
public class MachineDryer : IDryer {...} 

public class HandFolder : IFolder {...} 
public class MachineFolder : IFolder {...} 

maintenant dans l'application principale je quelque chose comme

var laundrySystem = _kernel.Get<ILaundrySystem>(someUserInput); 

Qu'est-ce qu'une bonne façon de configurer les liaisons nécessaires à quelque chose comme ça? Voici ce que j'ai pu trouver jusqu'ici (que je n'aime pas):

Bind<ILaundrySystem>().To<WasherDryerFolderSystem>() 
    .Named(MACHINEWASH_HANDDRY_HANDFOLD) 
    .WithConstructorArgument("washer", new MachineWasher()) 
    .WithConstructorArgument("dryer", new HandDryer()) 
    .WithConstructorArgument("folder", new HandFolder()); 

Au début, je ne pensais pas que ça avait l'air trop mal, mais quand tous les laveuses et sécheuses et les dossiers ont leurs propres dépendances, cela devient vite laid.

Cela me sent comme il devrait être un problème commun, mais je ne suis pas trouver tout ce qui est beaucoup d'aide. Est-ce que j'ai quelque chose de mal conçu?

Répondre

0

Vous pouvez utiliser un modèle d'usine:

public interface ILaundrySystemFactory 
{ 
    ILaundrySystem Create(string someUserInput); 
} 

public class LaundrySystemFactory : ILaundrySystemFactory 
{ 
    private readonly IKernel _kernel; 

    public LaundrySystemFactory(IKernel kernel){ 
     _kernel = kernel; 
    } 

    public ILaundrySystem Create(string someUserInput) 
    { 
     if(someUserInput){ 
      var washer = _kernel.Get<MachineWasher>(); 
      var dryer = _kernel.Get<HandDryer>(); 
      var folder = _kernel.Get<HandFolder>(); 
     } else {    
      var washer = _kernel.Get<DifferentWasher>(); 
      var dryer = _kernel.Get<DifferentDryer>(); 
      var folder = _kernel.Get<DifferentFolder>(); 
     } 
     return new WasherDryerFolderSystem(washer, dryer, folder); 
    } 
} 

puis simplement

private readonly ILaundrySystemFactory _laundrySystemFactory; 

ctor(ILaundrySystemFactory laundrySystemFactory){ 
    _laundrySystemFactory = laundrySystemFactory; 
} 

public UserInputMethod(string someUserInput) 
{ 
    var loundrySystem = laundrySystemFactory.Create(someUserInput); 
    var loundry = loundrySystem.DoLaundry(); 
} 

fixations:

Bind<ILaundrySystemFactory>().To<LaundrySystemFactory>(); 

(certains conteneurs de DI peuvent également besoin de quelque chose comme :)

Bind<MachineWasher>().To<MachineWasher>(); 
+0

Je dois injecter une laveuse/sécheuse/un dossier différent dans le WasherDryerFolderSystem en fonction de l'entrée de l'utilisateur, et à moins que quelque chose me manque, votre solution injecterait toujours un MachineWasher dans IWasher, un HandDryer dans IDryer et un HandFolder dans IFolder . J'ai besoin de ceux-ci pour changer. – TonyKMN

0

Faire un cours en béton avec des paramètres concrets dont vous avez besoin, les mettre comme des dépendances de la stratégie qui les utilisera en fonction des commentaires des utilisateurs. Ensuite instanciez-les tous avec un appel SINGLE pour une classe racine de résolution. La stratégie OFC peut être la racine de résolution elle-même, mais elle peut aussi dépendre de différentes racines de résolution. Exemple:

//DoLaundry based on user input 
public class WasherDryerFolderSystemStrategy 
{ 
    ctor(MachineWashingHandDringHandFoldingSystem first, 
     MachineWashingHandDringHandFoldingSystem second, 
     HandWashingHandDringHandFoldingWithBreakfastSystem third) { ... } 

    public void DoLaundry(int userInput) 
    { 
     if(userInput == 1) 
      first.DoLaundry(); 
     if(userInput == 2) 
      second.DoLaundry(); 
     if(userInput == 3) 
      third.DoLaundry(); 
    } 
} 

// MACHINEWASH_HANDDRY_HANDFOLD 
public class MachineWashingHandDringHandFoldingSystem : WasherDryerFolderSystem 
{ 
    public MachineWashingHandDringHandFoldingSystem 
     (MachineWasher machineWasher, HandDryer handDryer, HandFolder handFolder) : 
     base(machineWasher, handDryer, handFolder) 
    { 
    } 
} 

// HANDWASH_HANDDRY_HANDNOFOLD 
public class HandWashingHandDringHandFoldingSystem : WasherDryerFolderSystem 
{ 
    public MachineWashingHandDringHandFoldingSystem 
     (HandWasher machineWasher, HandDryer handDryer, HandFolder handFolder) : 
     base(machineWasher, handDryer, handFolder) 
    { 
    } 
} 

// HANDWASH_HANDDRY_HANDNOFOLD_WITHBREAKFAST 
public class HandWashingHandDringHandFoldingWithBreakfastSystem : WasherDryerFolderSystem 
{ 
    private readonly BreakfastMaker breakfastMaker 

    public MachineWashingHandDringHandFoldingSystem 
     (HandWasher machineWasher, HandDryer handDryer, HandFolder handFolder, BreakfastMaker brekfastMaker) : 
     base(machineWasher, handDryer, handFolder) 
    { 
     this.breakfastMaker = breakfastMaker 
    } 

    public overide void DoLaundry() 
    { 
     base.DoLaundry(); 
     brekfastMaker.AndMakeChipBreakAsWell(); 
    } 
} 

Veuillez noter que l'implémentation ci-dessus ne nécessite aucune configuration Ninject. Ninject va tout autobind ToSelf() avec la première utilisation (tant que ce n'est pas une interface).

En général aussi longtemps que vous n'avez pas besoin d'une sorte d'opérations composites/vrac avec de multiples implémentations, que vous devriez éviter les liaisons d'interface (et les interfaces du tout). Exemple d'opération composite:

// original WasherDryerFolderSystem refactored 
public class WasherDryerFolderSystem 
{ 
    private IEnumerable<IWasher> washers; 
    private IEnumerable<IDryer> dryers; 
    private IEnumerable<IFolder> folders; 

    public WasherDryerFolderSystem(
     IWasher[] washers, IDryer[] dryers, IFolder[] folders) 
    { 
     this.washers = washers; 
     this.dryers = dryers; 
     this.folders = folders; 
    } 

    // all inclusive 
    public virtual void DoLaundry() 
    { 
     foreach (var washer in washers) 
      washer.Wash(); 

     foreach (var dryer in dryers) 
      dryer.Dry(); 

     foreach (var folder in folders) 
      folder.Fold(); 
    } 
} 

J'espère que cela aide.