Search code examples
c#dependency-injectioninterfaceunity-container

Solving multiple interface implementation


I am in this situation where my service interface is being implemented by two service classes.

For example,

IFooService is implemented by FooService and FooWithExtraInfoService

Here is the interface:

public interface IFooService
{
    Foo GetEntity(string fieldName, stringFieldValue);
}

Here is FooService:

public class FooService: BarService,  IFooService
{
    public FooService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}

Here is FooWithExtraInfoService:

public class FooWithExtraInfoService: BarService, IFooService
{
    public FooWithExtraInfoService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //one possible option could be
        var foo = new FooService(logservice).GetEntity(fieldName, fieldValue)
        //do additional stuff
        foo.SomeField = "abc";
    }
}

As you can see one option could be creating new object of FooService and then telling unity to register type where IFooService is implemented by FooWithExtraInfoService.

Something like:

container.RegisterType<IFooService, FooWithExtraInfoService>();

But is there some other way where I don't have to create new object of FooService?

//one possible option could be
var fooService = new FooService(logservice).GetEntity(fieldName, fieldValue)
//do additional stuff

And let Unity handle it somehow?

Or should I create different interface for FooWithExtraInfoService?

I don't know what is the best way to approach this problem at this point.

Any suggestions would be helpful.


Solution

  • This seems like a good candidate for the decorator pattern.

    The decorator pattern wraps the existing service, adding additional functionality to it without having to make changes to it. This allows you to cleanly separate responsibilities of what FooService does from FooWithExtraInfoService and still allow the DI container to provide the "inner" instance.

    public class FooWithExtraInfoService : IFooService
    {
        private readonly IFooService fooService;
    
        public FooWithExtraInfoService(IFooService fooService)
        {
            if (fooService == null)
                throw new ArgumentNullException(nameof(fooService));
            this.fooService = fooService;
        }
    
        public Foo GetEntity(string fieldName, string fieldValue)
        {
            // call the decorated instance of IFooService
            var foo = this.fooService.GetEntity(fieldName, fieldValue);
            //do additional stuff
            foo.SomeField = "abc";
        }
    }
    

    Then you just need to wire it up with your DI container like:

    var instance = new FooWithExtraInfoService(new FooService(new LogService()));
    

    In Unity, this registration could be done like:

    container.RegisterType<ILogService, LogService>();
    
    // Register FooService as a named service
    container.RegisterType<IFooService, FooService>("foo");
    
    // Register FooWithExtraInfoService and inject FooService into it
    container.RegisterType<IFooService, FooWithExtraInfoService>(
        new InjectionConstructor(new ResolvedParameter<IFooService>("foo")));
    

    NOTE: An example of how you could make decorator registrations convention-based is in this answer.

    Unlike using inheritance, the decorator is loosely coupled from FooService. The ILogService does not need to be passed into the decorator only so it can be forwarded into the superclass constructor. Additionally, you can easily add another decorator class between FooWithExtraInfoService and FooService simply by changing the DI configuration.

    var instance = new FooWithExtraInfoService(
        new FooDecorator1(
        new FooService(new Logger())));