在哪里注入已经有构造函数的依赖组件

时间:2017-06-15 20:10:31

标签: c# dependency-injection business-logic

我有一些业务对象必须一起使用才能获得特定的结果。请查看以下非常简单的示例以供参考。

我的问题是:如何在Station类中使用DI获取对代理的引用?我最喜欢构造函数注入,但是这不可能,Station类已经将stationCode作为必需项。

有什么想法吗?

用法:

var station1 = new Station("xx");
var station2 = new Station("yy");
var route = new Route(station1, station2);

var length = route.GetLength();

public class Location
{
    public int Position {get; set;}
}

public interface IAgent
{
    Location GetLocation(string stationCode);
}

public class Station
{
    private string _stationCode;

    public Station(string stationCode)
    {
        _stationCode = stationCode;
    }

    public Location GetLocation()
    {
        // issue here: how to get a reference to the agent instance using DI
        _agent.GetLocation(_stationCode);
    }
}

public class Route
{
    private Station _station1;
    private Station _station2;

    public Route(Station station1, Station station2)
    {
        _station1 = station1;
        _station2 = station2;
    }

    public int GetLength()
    {
        var location1 = _station1.GetLocation();
        var location2 = _station2.GetLocation();

        result = location2.Position - location1.Position;

        return result;
    }
}

2 个答案:

答案 0 :(得分:1)

您的课程似乎遇到了身份危机。使用DI时,您应该只有两种类型来处理 - injectables and newables。你的Station类似乎是一个kludge,因为它既提供服务(有依赖关系)又有状态。为了使您的类对DI友好,您应该设计对状态(服务)执行某些操作的类提供状态的类。

路线

此类是可注入的 - 也就是说,它应该从DI容器连接。

public interface IRoute
{
    int GetLength(Station station1, Station station2);
}

public class Route : IRoute
{
    private readonly IAgent _agent;

    public Route(IAgent agent)
    {
        if (agent == null) throw new ArgumentNullException("agent");
        _agent = agent;
    }

    public int GetLength(Station station1, Station station2)
    {
        var location1 = _agent.GetLocation(station1.StationCode);
        var location2 = _agent.GetLocation(station2.StationCode);

        result = location2.Position - location1.Position;

        return result;
    }
}

这个类是新的 - 也就是说,你应该总是使用new关键字来实例化它。

public class Station
{
    private string _stationCode;

    public Station(string stationCode)
    {
        _stationCode = stationCode;
    }

    public string StationCode
    {
        get { return _stationCode; }
        // Optional: provide setter here
    }
}

用法

var station1 = new Station("xx");
var station2 = new Station("yy");

// IRoute is injected where you need to make the calculation
var length = _route.GetLength(station1, station2);

Route重命名为更合适的东西可能会更好,因为它不提供路线,而是计算路线长度。

  

坦率地说,如果你的Station类没有任何其他状态而不是单个字符串变量,那么消除该类可能更有意义,只需使用station1和{{1}的字符串}}。但这主要是个人品味。

答案 1 :(得分:0)

两种类型的处理概念,注射剂和新药,是一个好主意。但是当newables应该只包含有限的业务逻辑时,你就会偏离纯粹的面向对象的概念。为复杂域模型编写代码时,新的业务类包含业务逻辑和数据。我认为这也是问题的意图。 Station和Route类是简单的例子,实际上包含更多的逻辑和数据。

因此,我建议通过将存储代码与业务逻辑分开来更好地分离关注点。我看到了两种常见的解决方案。

  1. 当数据加载到内存中时,单独的 StationStore 类是一个可注入的加载站,并将它们存储在业务域的上下文中,例如。在静态属性中:

    public IEnumarable<Station> Station.Store { get; internal set; }
    
  2. 所有DI代码都可以隐藏在业务基类中。将DI依赖项放在那里不那么令人不安。因此,可以根据提供的模板类型在通用基类中解析代理。

    public class Station : BusinessClass<Station, StationAgent>
    {
        public string StationCode { get; internal set; }
        public Location Location { get; internal set; }
    
        public Station(string stationCode)
        {
            base.Load(stationCode, this);
        }
    }