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?
interface injection: the dependency provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.
In software engineering, dependency injection is a design pattern in which an object or function receives other objects or functions that it depends on. A form of inversion of control, dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs.
More specifically, dependency injection is effective in these situations: You need to inject configuration data into one or more components. You need to inject the same dependency into multiple components. You need to inject different implementations of the same dependency.
Dependency Injection (DI) is a software design pattern that allows us to develop loosely coupled code. DI is a great way to reduce tight coupling between software components. DI also enables us to better manage future changes and other complexity in our software. The purpose of DI is to make code maintainable.
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 ;-)
This may not be the best approach but it should work.
Add a property to each service that specifies the ServiceTypes
it represents:
public interface IService
{
public ServiceTypes Type { get; }
public int DoWork();
}
Implement the property in each class:
public class Service1 : IService
{
public ServiceTypes Type { get { return ServiceTypes.Service_One; } }
public void DoWork()
{
return 1;
}
}
Then, register all the implementations of your service in the container and inject them in your handler. From there, select the implementation based on a property from the command:
container.For<IService>().Use<Service1>("service1");
container.For<IService>().Use<Service2>("service2");
Add the required ServiceType
in the command class:
public class Command1
{
// Other command properties
public ServiceTypes Service { get; set; }
}
And in the command handler:
public class CommandHandler : ICommandHandler<Command1>
{
private readonly IEnumerable<IService> _services;
public CommandHandler(IService[] services)
{
_servies = services;
}
public void Handle(Command1 command)
{
var service = _services.Single(s => s.Type == command.Service);
service.DoWork();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With