Search code examples
c#design-patternsdependency-injectiondependencies

Dependency injection of One interface multiple implementations


I have following situation:

IMachineService with method CreateMachine() and I have service for every kind of machine like MachineServiceTypeA createMachine() and so on...

and the same from other side I have interface for all types of machines like IMachine with method Start() and Stop()

I am thinking this way - I have to add Factory to class with Services and Factory to class Machines to be able to inject them properly with dependency injection.

I will have something like this -

services.AddTransient<IMachine, MachineA>();
services.AddTransient<IMachine, Machineb>();
services.AddTransient<IMachineFactory, MachineFactory>();
services.AddScoped<IMachineService, MachineAService>();
services.AddScoped<IMachineService, MachineBService>();
services.AddTransient<IMachineServiceFactory, MachineServiceFactory>();

This is my initial idea, but I don't thing it is good. Could you suggest me some options please, I want to be able to create for example 5 machines of type A and 3 machines of type B all of them in same collection and to keep code simple.


Solution

  • I believe if you use the following example of creation instances, then you will always get the last implementation of an interface:

    services.AddTransient<IMachine, MachineA>();
    services.AddTransient<IMachine, Machineb>();
    services.AddTransient<IMachineFactory, MachineFactory>();
    services.AddScoped<IMachineService, MachineAService>();
    services.AddScoped<IMachineService, MachineBService>();
    services.AddTransient<IMachineServiceFactory, MachineServiceFactory>();
    

    So I believe we can create a factory and just try to get instance based on a desired type. Let me show an example.

    This is the abstraction of machines:

    public interface IMachine { }
    

    And they are concrete implementations:

    public class MachineA : IMachine
    { }
    
    public class MachineB : IMachine
    { }
    

    Then this is how abstraction of factory would look:

    public interface IMachineFactory 
    {
        IMachine GetInstanceByType(MachineType machineType);
    }
    

    And its concrete implementation:

    public class MachineFactory : IMachineFactory
    {
        private Dictionary<MachineType, IMachine> _machineByType;
    
        public MachineFactory(MachineA machineA, MachineB machineB)
        {
            _machineByType = new()
            {
                { MachineType.A, machineA },
                { MachineType.B, machineB },
            };
        }
    
        public IMachine GetInstanceByType(MachineType machineType) => 
            _machineByType[machineType];
    }
    

    And these are type of machines:

    public enum MachineType
    {
        A, B
    }
    

    Then instantiation of dependencies would look like this:

    services.AddTransient<MachineA>();
    services.AddTransient<MachineB>();
    services.AddTransient<IMachineFactory, MachineFactory >();      
    

    and it is possible to use the above code like this:

    private readonly IMachineFactory _machineFactory;
    
    public FooController(IMachineFactory machineFactory)
    {
        _machineFactory = machineFactory;
    }
    
    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        IMachine foo = _machineFactory.GetInstanceByType(MachineType.A);
        // ... other code is omitted for the brevity
    }