2016-11-03 1 views
0

Я столкнулся с тем, что, по моему мнению, является общей проблемой, связанной с инъекциями. У меня возникли проблемы с поиском соответствующих примеров, и мне не нравится лучшее решение, которое я смог придумать.Как настроить ninject для ввода различных типов зависимостей в один класс?

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 {...} 

Теперь в главном приложении у меня есть что-то вроде

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

Что такое хороший способ для настройки привязок, необходимых для чего-то вроде этого? Вот что я смог придумать до сих пор (что мне не нравится):

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

Сначала я не думал, что это выглядело слишком плохо, но когда Стиральные машины и сушилки и папки все имеют их собственные зависимости, это быстро становится уродливым.

Мне кажется, что это должна быть общая проблема, но я не нахожу ничего полезного. Есть ли у меня что-то неправильное?

ответ

0

Вы можете использовать шаблон фабрики:

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); 
    } 
} 

, а затем просто

private readonly ILaundrySystemFactory _laundrySystemFactory; 

ctor(ILaundrySystemFactory laundrySystemFactory){ 
    _laundrySystemFactory = laundrySystemFactory; 
} 

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

привязок:

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

(некоторые DI контейнеры также может понадобиться что-то вроде :)

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

Мне нужно ввести другую систему стиральной машины/сушилки/папки в систему WasherDryerFolderSystem на основе ввода пользователем, и если я ничего не пропущу, ваше решение всегда будет вводить MachineWasher в IWasher, HandDryer в IDryer и HandFolder в IFolder , Мне нужно, чтобы они изменились. – TonyKMN

0

Составьте конкретные классы с конкретными параметрами, которые вам нужны, ставьте их как зависимости стратегии, которые будут использовать их на основе пользовательского ввода. Затем создайте экземпляр их всех с помощью SINGLE, чтобы вызвать класс корня разрешения. Стратегия OFC может быть самой корней разрешения, но она также может быть зависимой от другого корня resoultion. Пример:

//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(); 
    } 
} 

Обратите внимание, что реализация, приведенная выше, не требует никакой конфигурации Ninject. Ninject будет автоматически сохранять все ToSelf() с первого использования (пока это не интерфейс).

В общем, до тех пор, пока вам не нужны какие-либо сложные/массовые операции с несколькими реализациями, вам следует избегать связывания интерфейсов (и интерфейсов вообще). Составной пример операции:

// 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(); 
    } 
} 

Надеюсь, что это поможет.

Смежные вопросы