I have an interface in my project that 2 classes implement it:
public interface IService
{
int DoWork();
}
public class Service1:IService
{
public int DoWork()
{
return 1;
}
}
public class Service2:IService
{
public int DoWork()
{
return 2;
}
}
I have a command handler that depends on IService
too:
public CommandHandler1:ICommandHandler<CommandParameter1>
{
IService _service;
public CommandHandler1(IService service)
{
_service = service
}
public void Handle()
{
//do something
_service.DoWork();
//do something else
}
}
public interface ICommandHandler<TCommandParameter>
where TCommandParameter :ICommandParameter
{
void Handle(TCommandParameter parameter);
}
public interface ICommandParameter
{
}
I want to inject Service1
or Service2
to my CommandHandler1
based on user selection. suppose that I have an enum
and user could select a value from it:
public enum Services
{
Service_One,
Service_Two
}
If user selects Service_One
I want inject Service1
to my command handler and If he selects Service_Two
I want inject Service2
to the command handler.
I know that I can use named instances, and then call ObjectFactory.GetInstance<IService>().Named("Service1")
for example, but
Is there any way to implement this by StructureMap
and prevent using Service Locator
pattern?
Prevent building your object graphs using runtime conditions. Object graphs should be fixed. Use runtime decisions to determine the path through the object graph.
What you seem to be missing here is an abstraction that allows delegating the request to the correct IService
implementation; let's call it IServiceDispatcher
:
interface IServiceDispatcher
{
int DoWork(Services data);
}
sealed class ServiceDispatcher : IServiceDispatcher
{
private readonly IService service1;
private readonly IService service2;
// NOTE: Feel free to inject the container here instead, as long as
// this class is part of your composition root.
public ServiceDispatcher(IService service1, IService service2)
{
this.service1 = service1;
this.service2 = service2;
}
public int DoWork(Services data)
{
return this.GetService(data).DoWork();
}
private IService GetService(Services data)
{
switch (data)
{
case Services.Service_One: return this.service1;
case Services.Service_Two: return this.service2;
default: throw new InvalidEnumArgumentException();
}
}
}
Now your CommandHandler1
can depend on IServiceDispatcher
:
public CommandHandler1 : ICommandHandler<CommandParameter1>
{
private readonly IServiceDispatcher serviceDispatcher;
public CommandHandler1(IServiceDispatcher serviceDispatcher)
{
this.serviceDispatcher = serviceDispatcher;
}
public void Handle(CommandParameter1 commandParameter)
{
//do something
this.serviceDispatcher.DoWork(commandParameter.Service);
//do something else
}
}
Do note that IServiceDispatcher
is a really ugly name that technically describes what's going on. This is a bad idea, because the interface should functionally describe what you want. But since you didn't supply any domain-specific context to your question, this is the best name I can come up with ;-)