Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection with Interface implemented by multiple classes

Update: Is there a way to achieve what I'm trying to do in an IoC framework other than Windsor? Windsor will handle the controllers fine but won't resolve anything else. I'm sure it's my fault but I'm following the tutorial verbatim and objects are not resolving with ctor injection, they are still null despite doing the registers and resolves. I've since scrapped my DI code and have manual injection for now because the project is time sensitive. Hoping to get DI worked out before deadline.


I have a solution that has multiple classes that all implement the same interface

As a simple example, the Interface

public interface IMyInterface {
    string GetString();
    int GetInt();
   ...
}

The concrete classes

public class MyClassOne : IMyInterface {
    public string GetString() {
        ....
    }
    public int GetInt() {
        ....
    }
}

public class MyClassTwo : IMyInterface {
    public string GetString() {
        ....
    }
    public int GetInt() {
        ....
    }
}

Now these classes will be injected where needed into layers above them like:

public class HomeController {

    private readonly IMyInterface myInterface;

    public HomeController() {}

    public HomeController(IMyInterface _myInterface) {
        myInterface = _myInterface
    }
    ...
}

public class OtherController {

    private readonly IMyInterface myInterface;

    public OtherController() {}

    public OtherController(IMyInterface _myInterface) {
        myInterface = _myInterface
    }
    ...
}

Both controllers are getting injected with the same interface.

When it comes to resolving these interfaces with the proper concrete class in my IoC, how do I differentiate that HomeController needs an instance of MyClassOne and OtherController needs an instance of MyClassTwo?

How do I bind two different concrete classes to the same interface in the IoC? I don't want to create 2 different interfaces as that breaks the DRY rule and doesn't make sense anyway.

In Castle Windsor I would have 2 lines like this:

container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>());
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>());

This won't work because I will only ever get a copy of MyClassTwo because it's the last one registered for the interface.

Like I said, I don't get how I can do it without creating specific interfaces for each concrete, doing that breaks not only DRY rules but basic OOP as well. How do I achieve this?


Update based on Mark Polsen's answer


Here is my current IoC, where would the .Resolve statements go? I don' see anything in the Windsor docs

public class Dependency : IDependency {

    private readonly WindsorContainer container = new WindsorContainer();

    private IDependency() {
    }

    public IDependency AddWeb() {
        ...

        container.Register(Component.For<IListItemRepository>().ImplementedBy<ProgramTypeRepository>().Named("ProgramTypeList"));
        container.Register(Component.For<IListItemRepository>().ImplementedBy<IndexTypeRepository>().Named("IndexTypeList"));

        return this;
    }

    public static IDependency Start() {
        return new IDependency();
    }
}
like image 894
CD Smith Avatar asked Jun 11 '12 15:06

CD Smith


People also ask

Can an interface have multiple implementations?

Java does not support "multiple inheritance" (a class can only inherit from one superclass). However, it can be achieved with interfaces, because the class can implement multiple interfaces. Note: To implement multiple interfaces, separate them with a comma (see example below).

Can we register multiple implementation of the same interface via DI?

So if you only use one implementation in your application after the application started, please register the implementation according to the configuration in DI container (Startup. Configure). If at application runtime, you need to choose from multiple implementations, you can use this solution without problem.

Can multiple classes implement the same interface in Java?

A class can implement multiple interfaces and many classes can implement the same interface.

Can an interface be implemented by multiple classes C#?

A class or struct can implement multiple interfaces. A class can inherit a base class and also implement one or more interfaces.


2 Answers

I hope you can use service overrides.

Ex.

container.Register(
    Component.For<IMyService>()
        .ImplementedBy<MyServiceImpl>()
        .Named("myservice.default"),
    Component.For<IMyService>()
        .ImplementedBy<OtherServiceImpl>()
        .Named("myservice.alternative"),

    Component.For<ProductController>()
        .ServiceOverrides(ServiceOverride.ForKey("myService").Eq("myservice.alternative"))
);

public class ProductController
{
    // Will get a OtherServiceImpl for myService.
    // MyServiceImpl would be given without the service override.
    public ProductController(IMyService myService)
    {
    }
}
like image 199
VJAI Avatar answered Oct 23 '22 09:10

VJAI


You should be able to accomplish it with named component registration.

container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>().Named("One"));
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>().Named("Two"));

and then resolve them with

kernel.Resolve<IMyInterface>("One");

or

kernel.Resolve<IMyInterface>("Two");

See: To specify a name for the component

like image 31
Mark Polsen Avatar answered Oct 23 '22 09:10

Mark Polsen