I've run into what I believe must be a common dependency injection-related problem. I'm having trouble finding relevant examples, and I do not like the best solution I've been able to come up with.
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 {...}
Now in the main app I have something like
var laundrySystem = _kernel.Get<ILaundrySystem>(someUserInput);
What is a good way to configure the bindings required for something like this? Here's what I've been able to come up with thus far (that I don't like):
Bind<ILaundrySystem>().To<WasherDryerFolderSystem>()
.Named(MACHINEWASH_HANDDRY_HANDFOLD)
.WithConstructorArgument("washer", new MachineWasher())
.WithConstructorArgument("dryer", new HandDryer())
.WithConstructorArgument("folder", new HandFolder());
At first I didn't think this looked too bad, but when Washers and Dryers and Folders all have their own dependencies, this quickly gets ugly.
This feels to me like it should be a common problem, but I'm not finding anything that's much help. Do I have something designed incorrectly?
You could use a factory pattern:
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);
}
}
and then simply
private readonly ILaundrySystemFactory _laundrySystemFactory;
ctor(ILaundrySystemFactory laundrySystemFactory){
_laundrySystemFactory = laundrySystemFactory;
}
public UserInputMethod(string someUserInput)
{
var loundrySystem = laundrySystemFactory.Create(someUserInput);
var loundry = loundrySystem.DoLaundry();
}
bindings:
Bind<ILaundrySystemFactory>().To<LaundrySystemFactory>();
(some DI containers might also need something like:)
Bind<MachineWasher>().To<MachineWasher>();