13

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?

Masoud
  • 8,020
  • 12
  • 62
  • 123
  • What would happen if you inject `Service2` into `Command1`? Would that break `Command1` or would keep functioning correctly? – Steven Aug 31 '15 at 10:36
  • @Steven: It works fine in code point of view, but it fails in business rule point of view. – Masoud Aug 31 '15 at 10:48
  • Can you add the definition of the `ICommandHandler` interface to your question? – Steven Aug 31 '15 at 11:06
  • How many IService-like interfaces you have? How many methods they have? How do those methods look like? Can Command1 have different dependencies than IService? Are you expecting more types of IService implementations? What is X in ICommandHandler ? Is the Services enum value available to Command or is it specified somewhere else? – Euphoric Aug 31 '15 at 11:10

3 Answers3

10

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

Steven
  • 166,672
  • 24
  • 332
  • 435
  • What if Command1 needs more than IServiceDispatcher as dependency? – Euphoric Aug 31 '15 at 10:59
  • @Euphoric: I'm not sure I understand the problem. You can inject any dependency in the constructor. The constructor will be auto-wired with all its dependency by StructureMap. – Steven Aug 31 '15 at 11:05
  • Sorry, I saw it wrong. Now when I look at it. Where did command.Service came from? And are you saying IServiceDispatcher has to copy every method from IService while adding Services enum to every method signature? To me, this looks like lots of overhead for this. – Euphoric Aug 31 '15 at 11:08
  • @Euphoric: According to OP the enum is "based on user selection". This means that this value is part of the command and set by the consumer who has created that command. – Steven Aug 31 '15 at 11:11
  • @Euphoric: "And are you saying IServiceDispatcher has to copy every method from IService". If `IService` has more than one method, you are violating the [ISP](https://en.wikipedia.org/wiki/Interface_segregation_principle). "while adding Services enum to every method signature". The problem with that approach is that `Command1` becomes responsible of dispatching, which probably shouldn't be his responsibility. But to be honest, the OP hardly given us enough context to know which option is best in his situation. – Steven Aug 31 '15 at 11:15
  • How are you suggesting to set up creation of ServiceDispatcher so that each service subtype is wired up to correct constructor parameter? – Euphoric Aug 31 '15 at 11:53
  • @Euphoric: Depending on your container, there are multiple ways to do this, but what works with all containers is to register a delegate that manually news up the dispatcher, while the dependencies are resolved from the container, e.g. `container.Register(c => new ServiceDispatcher(c.Resolve("s1"), c.Resolve("s2"))`. – Steven Aug 31 '15 at 11:59
  • This might sound like a strange question, but would it make sense for the dispatcher itself to implement `IService`? It's providing the same method in `DoWork`, yet implementing a different interface. I've run into something similar in the past and went with the same interface. Say I had an English implementation, a Portuguese implementation, and a "Localized" implementation. The localized version would pick the appropriate localization, but still provide the same interface to the client. I thought that was nice because of how transparent it was. – julealgon Sep 19 '17 at 00:12
  • It also allowed me to incrementally add localized versions of existing interfaces, without breaking any of the clients. Imagine that you had to add this decision making logic midway through the application. If we go with a separate `IDispatcher` interface, you now need to update potentially many places and tests in the application to switch from the old ÌService` into the new interface. By using the same contract, you remove this problem. – julealgon Sep 19 '17 at 00:14
  • Looking closer to it, your example is slightly different because you are taking an additional parameter in the `IDispatcher.DoWork` that you don't take in the `IService` method... the difference from my use case was that I was able to "make the decision" by injecting a class with context, instead of taking one as parameter. Would still like to hear what you have to say on this one. Say for instance that I had a class with context of the user selection that I could inject into the dispatcher. – julealgon Sep 19 '17 at 00:19
  • 1
    @julealgon not a strange question at all. What you are describing is a Proxy, Decorator or Composite. All reuse the same abstraction as the original object. Reusing the interface should be your preferred method, since it prevents the client from knowing anyrhing about underlying complexity. As you already noticed, this is not always possible and using a new abstraction that hides the old is the next best thing (compared to an Abstract Factory for instance). – Steven Sep 19 '17 at 05:59
1

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();
    }
}
RePierre
  • 9,358
  • 2
  • 20
  • 37
  • I don't think switching from Command to Command-Handler patter in good suggestion. – Euphoric Aug 31 '15 at 07:10
  • This reminds me of Autofac's `Meta<>`; i.e. metadata about a component that can be queried *before* the component is chosen. Not sure if StructureMap has something similar. – stakx - no longer contributing Aug 31 '15 at 07:11
  • 2
    @Euphoric, I don't think it's a switch - `ICommandHandler` from the question is (at least for me) quite a direct hint to Command-Handler. – RePierre Aug 31 '15 at 08:16
  • But it looks more like simple command, even if it is named like that the actual "command" that would go with it is nowhere in sight. For example, your "handler" accepts the "command" as a parameter. While his handler is all alone. – Euphoric Aug 31 '15 at 08:17
1

I would create a factory, that has reference to IContext and uses it to resolve the concrete service dependency.

public interface ICommandFactory
{
    Command1 CreateCommand(Services serviceType);
}

public class CommandFactory : ICommandFactory
{
    private readonly IContext _context;

    public CommandFactory(IContext context)
    {
        _context = context;
    }

    public Command1 CreateCommand(Services serviceType)
    {
        IService service;
        switch(serviceType)
        {
            case Services.Service_One: service = _context.GetInstance<Service1>();
                break;
            case Services.Service_Two: service = _context.GetInstance<Service2>();
                break;
            default:
                throw new ArgumentOutOfRangeException("serviceType", serviceType, null);
        }

        return new Command1(service);
    }
}

And then, you register and use it like this:

var container = new Container(_ =>
{
    _.For<ICommandFactory>().Use(context=>new CommandFactory(context));
});

var factory = container.GetInstance<ICommandFactory>();

var command = factory.CreateCommand(Services.Service_One);
command.Handle();

First, the responsibility of picking the right service is separate from the command itself. It also allows command to have different dependencies on top of the service itself, just call _context.GetInstance<TypeOfDependency>().

About this being same as Service Locator. The major problem of service locator is that it hides dependencies. This is not case here, because the one calling the command explicitly states dependency on the CommandFactory class. And if interface is introduced for the factory class (turning it into AbstractFactory pattern), then the implementation itself can become part of the dependency resolution strategy. Eg. it will be in same place as the dependency framework itself. Thanks to this there is no Service Locator (static or interface) within the domain model.

Euphoric
  • 12,645
  • 1
  • 30
  • 44
  • So in essence, you are advising to use the [Service Locator pattern](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/)? – Steven Aug 31 '15 at 10:37
  • @Steven I knew someone is going to say this. No, that is not a service locator if the context is not static and if factory class is part of "dependency resolution" module. – Euphoric Aug 31 '15 at 10:58
  • 1
    I'm afraid you are incorrect. According to Martin Fowler, a Service Locator [is](http://martinfowler.com/articles/injection.html) "an object that knows how to get hold of all of the services that an application might need". Whether or not it is a static class or an abstraction is irrelevant and both have the [same set of downsides](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/). – Steven Aug 31 '15 at 11:37
  • @Steven If you use that as definition then even DI container counts as Service Locator. – Euphoric Aug 31 '15 at 11:47
  • That completely depends on *how* you use the container. See [this article](http://blog.ploeh.dk/2011/08/25/ServiceLocatorrolesvs.mechanics/) for more information. TLDR; If you use the `Container` solely inside your [Composition Root](http://blog.ploeh.dk/2011/07/28/CompositionRoot/), its use is not a form of Service Location. – Steven Aug 31 '15 at 11:57
  • @Steven "If you use the Container solely inside your Composition Root, its use is not a form of Service Location" Which is exactly what is happening here. – Euphoric Aug 31 '15 at 11:59
  • Not completely. Since `Command1` needs a dependency on `CommandFactory`, `CommandFactory` can't be part of the composition root. If however, you let `CommandFactory` implement `ICommandFactory`, you can let `Command1` depend on `ICommandFactory` while moving the `CommandFactory` inside the Composition Root. If you add the interface to your answer, I will +1 you. – Steven Aug 31 '15 at 12:01
  • @Steven I added the interface (which should be no-brainer for anyone). But also note that dependencies you described are wrong. Its CommandFactory that need dependency on Command1. Not other way around. – Euphoric Aug 31 '15 at 13:40
  • Oh, I'm sorry. I didn't pay close attention. I still disagree with your solution. I happen to know what kind of design OP is using ([this one](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91)). He doesn't use the Command pattern, he uses the 'command/handler' pattern. What OP calls 'a command' is actually a handler (it even implements `ICommandHandler`). Handlers should be resolved by the container, not by a custom factory. So if your factory returns an `IService`, I can agree. Example: `IService CreateService(Services serviceType)`. – Steven Aug 31 '15 at 13:46