解决多接口实现

Solving multiple interface implementation

我处于这种情况,我的服务接口由两个服务实现 类。

例如,

IFooServiceFooServiceFooWithExtraInfoService[实现=55=]

界面如下:

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

这里是FooService:

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

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

这里是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";
    }
}

如您所见,一个选项可能是创建 FooService 的新对象,然后告诉 unity 注册类型,其中 IFooServiceFooWithExtraInfoService 实现。

类似于:

container.RegisterType<IFooService, FooWithExtraInfoService>();

但是有没有其他方法可以让我不必创建 FooService 的新对象?

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

让 Unity 以某种方式处理它?

或者我应该为 FooWithExtraInfoService 创建不同的界面吗?

目前我不知道解决这个问题的最佳方法是什么。

任何建议都会有所帮助。

鉴于两者都继承自 BarService,创建一个实现接口的中间类型 FooServiceBase

public abstract class FooServiceBase : BarService, IFooService
{
    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}

并让 FooWithExtraInfoServiceFooService 继承。

我相信在你的情况下你应该使用 Composition ...意味着有一个 属性 类型 FooService 而不是像下面这样因为你只想使用 GetEntity() 方法并且无意扩展它

public class FooWithExtraInfoService: BarService
{
   public FooService FooService { get; set; }

当您不能总是单独依赖接口来定义您的 service-consumers 要求的行为时,一种替代方法是为 DI 注册一个或两个具体实现。

然后任何可以安全地依赖于更简单的 IFooService 的 class 都可以声明对它的依赖,而那些你知道需要 FooWithExtraInfoService 的额外功能的人可以依赖那反而。 FooWithExtraInfoService 甚至可以声明对 IFooService 的依赖以注入更简单的实现。

基本上,接口服务很有用,但不要在每种情况下都尝试使用它们。

这似乎是 decorator pattern 的一个很好的候选者。

装饰器模式包装现有服务,为其添加额外的功能,而无需对其进行更改。这允许您清楚地将 FooService 的职责与 FooWithExtraInfoService 的职责分开,并且仍然允许 DI 容器提供 "inner" 实例。

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";
    }
}

然后您只需要将它与您的 DI 容器连接起来,例如:

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

在 Unity 中,可以这样注册:

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.

与使用继承不同,装饰器与 FooService 松耦合ILogService 不需要传递到装饰器中,所以它可以转发到 superclass 构造函数中。此外,只需更改 DI 配置,您就可以在 FooWithExtraInfoServiceFooService 之间轻松添加另一个装饰器 class。

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

这似乎 FooWithExtraInfoService 应该是 FooService,但是有额外的信息,对吗?

那么,实际上 使 成为具有额外信息的 FooService class。给 FooService 中的 GetEntity 函数赋予 virtual 关键字,它可以在子 classes 中被覆盖。然后,这允许您在 FooWithExtraInfoService 中有一个新的覆盖,它可以简单地调用其父实现。

改编FooService class:

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

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

实施:

public class FooWithExtraInfoService: FooService
{
    public FooWithExtraInfoService(ILogService logservice): base(logservice)
    {
    }

    public override Foo GetEntity(string fieldName, string fieldValue)
    {
        Foo foo = base.GetEntity(fieldName, fieldValue)
        //do additional stuff
        foo.SomeField = "abc";
    }
}