解决多个接口实现

时间:2018-03-08 11:28:32

标签: c# dependency-injection interface unity-container

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

例如,

IFooService FooService FooWithExtraInfoService

实施

这是界面:

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 的新对象吗?

FooWithExtraInfoService

让Unity以某种方式处理它?<​​/ p>

或者我应该为Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.web.servlet.mvc.method.annotation.SseEmitter' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1466) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1097) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1059) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:589) ... 24 more 创建不同的界面吗?

我现在还不知道解决这个问题的最佳方法是什么。

任何建议都会有所帮助。

5 个答案:

答案 0 :(得分:1)

这似乎是decorator pattern的好候选人。

装饰器模式包装现有服务,为其添加其他功能,而无需对其进行更改。这使您可以清楚地分离FooServiceFooWithExtraInfoService所做的责任,并仍然允许DI容器提供“内部”实例。

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

注意:您可以在this answer中使用基于约定的装饰器注册的示例。

与继承不同,装饰器与FooService 松散耦合ILogService不需要仅传递给装饰器,因此可以将其转发到超类构造函数中。此外,只需更改DI配置,即可在FooWithExtraInfoServiceFooService之间轻松添加另一个装饰器类。

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

答案 1 :(得分:0)

鉴于两者都继承自import React from 'react'; import { connect } from 'react-redux'; import { removeItem, selectItem } from '../actions/items'; import { Badge, ListGroup, ListGroupItem, Button } from 'reactstrap'; const stylesForActiveItem = { borderLeft: '4px solid red', transition: 'all .5s', marginLeft: '-4px', borderRadius: '0' } class Item extends React.Component { constructor(props) { super(props); } render() { const { removeItem, selectItem, id, title, selected } = this.props; return ( <ListGroup className="Item"> <ListGroupItem onClick={() => selectItem({ id })} className={selected ? 'Item__text active-item' : 'Item__text'} >{title} <Badge className="Item__badge">14</Badge> </ListGroupItem> <Button className="Item__btn" onClick={() => removeItem({ id })}>Delete</Button> </ListGroup> ); } } const mapDispatchToProps = (dispatch) => ({ removeItem: (id) => dispatch(removeItem(id)), selectItem: (id) => dispatch(selectItem(id)) }) export default connect(null, mapDispatchToProps)(Item); ,创建一个实现接口的中间类型BarService

FooServiceBase

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

答案 2 :(得分:0)

我相信您的情况应该使用Composition ...意味着拥有FooService类型的属性,而不是像下面那样,因为您只想使用GetEntity()方法而无意扩展它

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

答案 3 :(得分:0)

当您无法单独依靠界面来定义服务消费者所需的行为时,另一种方法是为DI注册一个或两个具体实现。

然后,任何可以安全依赖于更简单的FooWithExtraInfoService的类都可以声明对它的依赖,而那些你知道需要来自FooWithExtraInfoService的附加功能的类可以依赖于它。 IFooService甚至可以声明对{{1}}的依赖,以注入更简单的实现。

基本上,界面服务很有用,但在每种情况下都不要试图使用界面服务。

答案 4 :(得分:0)

FooWithExtraInfoService似乎是FooService,但有额外的信息,对吧?

那么,实际上使成为一个带有额外信息的FooService类。在GetEntity FooService关键字中提供virtual函数,并且可以在子类中重写它。然后,您可以在FooWithExtraInfoService中使用新的覆盖,只需调用其父实现。

改编后的FooService课程:

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