如何配置ninject将不同的依赖类型注入到同一个类中?

问题描述 投票:0回答:2

我遇到了我认为一定是常见的依赖注入相关问题。我无法找到相关示例,而且我不喜欢我能提出的最佳解决方案。

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

起初我并不认为这看起来太糟糕,但是当洗衣机、烘干机和文件夹都有自己的依赖项时,这很快就会变得丑陋。

我觉得这应该是一个常见问题,但我没有找到任何有帮助的东西。我是否有什么设计不正确的地方?

c# .net dependency-injection inversion-of-control ninject
2个回答
1
投票

您可以使用工厂模式:

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
投票

使用您需要的具体参数创建一个具体的类,将它们作为策略的依赖项,策略将根据用户输入使用它们。接下来,通过单个调用解析根类来实例化它们。 OFC策略可以是解析根本身,也可以是不同解析根的依赖。示例:

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

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.