解决多接口实现
Solving multiple interface implementation
我处于这种情况,我的服务接口由两个服务实现 类。
例如,
IFooService
由FooService
和FooWithExtraInfoService
[实现=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 注册类型,其中 IFooService
由 FooWithExtraInfoService
实现。
类似于:
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
}
}
并让 FooWithExtraInfoService
和 FooService
继承。
我相信在你的情况下你应该使用 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 配置,您就可以在 FooWithExtraInfoService
和 FooService
之间轻松添加另一个装饰器 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";
}
}
我处于这种情况,我的服务接口由两个服务实现 类。
例如,
IFooService
由FooService
和FooWithExtraInfoService
[实现=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 注册类型,其中 IFooService
由 FooWithExtraInfoService
实现。
类似于:
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
}
}
并让 FooWithExtraInfoService
和 FooService
继承。
我相信在你的情况下你应该使用 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 配置,您就可以在 FooWithExtraInfoService
和 FooService
之间轻松添加另一个装饰器 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";
}
}