未为 DI/IoC 设置 StructureMap 和对象

2024-01-01

我有一种情况,我创建了一个工厂方法来创建一个对象。但是,该对象具有需要在创建对象之前执行的样板代码。修复这部分设计超出了这个问题的范围。

此外,当创建对象时,屏幕上的状态显示也会更新。这要求在创建此对象之前先实例化此状态显示并使其可见,并且应用程序处于运行状态。它作为依赖项传递给工厂。

我正在使用 StructureMap v3.1.4.143。

所以,这就是我在正常世界中(IoC 之前)要做的事情:

GraphicsInterface GetGraphics()
{
    VideoDevicesList.GetVideoDevices();

    // Some logic here to determine the device to use...
    // Also, a status display is being updated to inform the user of 
    // what's happening at this point.
    VideoDevice device = ...;

    // The second parameter is a constant value, but the first is not.
    return new GraphicsInterface(device, featureLevels.FL5);
}

看起来很简单,但理想情况下我希望能够通过注入传递该图形对象,因为很多地方都需要它。

因此,在结构图中,我创建了一个工厂函数来执行上述操作。然而这却给我带来悲伤。

new Container(obj =>
      {
          // This is passed to the object that depends on it.
          // I've just left it out for brevity.
          // It'd go something like:  _graphics = _getGraphicsFactory();
          // where _getGraphicsFactory is the factory function below.
          For<Func<IStatusDisplay, GraphicsInterface>>
             .Use<Func<IStatusDisplay, GraphicsInterface>>(GetGraphics);
      }

只有这给了我一个有关 GraphicsInterface 未注册的错误。没关系,我应该能够注册 GraphicsInterface 对象。除了我无法注册 GraphicsInterface 因为构造函数需要两个参数,其中之一must在创建对象之前进行查询,并且只能通过上面的 GetVideoDevices 方法进行设置,当我调用 _getGraphicsFactory() 时,StructureMap 似乎尝试为我创建对象(这很奇怪,我希望它执行我的函数创建对象)。

我什至尝试在 GetVideoDevices 方法中像这样调用 GetInstance:

_container
    .With<VideoDevice>(device)
    .With<FeatureLevel>(FeatureLevel.FL5)
    .GetInstance<Graphics>();

但没有骰子...

那么,有人知道我如何让它发挥作用吗?


每当您绞尽脑汁试图弄清楚如何在运行时创建实例时,您都需要退后一步,寻找适合该问题的设计模式。 DI 的目的是构成应用程序,但控制运行时行为应该是应用程序设计的一部分 - 即运行的部分after应用程序已组成。

在这种特殊情况下,抽象工厂 http://sourcemaking.com/design_patterns/abstract_factory会很合适。它允许您将组合服务(通过构造函数注入的服务)与运行时服务(作为方法参数传递的服务)分开。

但是,您应该限制工厂只做一件事 - 创建运行时实例。所有其他工作都应该是其他服务的一部分。这为您提供了一种将运行时对象注入到服务中的干净方法,并且仍然允许独立于此步骤测试服务行为。

public interface IGraphicsFactory
{
    GraphicsInterface Create(VideoDevice device);
    void Release(GraphicsInterface graphicsInterface);
}

public class GraphicsFactory : IGraphicsFactory
{
    private readonly FeatureLevel featureLevel;

    // Parameters injected are done so by the DI container
    public GraphicsFactory(FeatureLevel featureLevel)
    {
        this.featureLevel = featureLevel;
    }

    // Parameters passed are part of the application runtime state
    public GraphicsInterface Create(VideoDevice device)
    {
        return new GraphicsInterface(device, this.featureLevel);
    }

    // Method for releasing disposable dependencies (if any)
    public void Release(GraphicsInterface graphicsInterface)
    {
        var disposable = graphicsInterface as IDisposable;
        if (disposable != null)
            disposable.Dispose();
    }
}

然后,您的工厂可以在应用程序组合期间提供给服务,并且可以在运行时创建 GraphicsInterface 的运行时实例。根据您的要求,通过将其注入多个服务的构造函数,可以在多个位置轻松完成此操作。

public class SomeService : ISomeService
{
    private readonly IGraphicsFactory graphicsFactory;

    public SomeService(IGraphicsFactory graphicsFactory)
    {
        if (graphicsFactory == null)
            throw new ArgumentNullException("graphicsFactory")

        this.graphicsFactory = graphicsFactory;
    }

    public void DoSomething()
    {
        // Get video device here. It will likely be best to 
        // delegate that to another specialized service
        // that is injected into this class.
        VideoDevice device = ...;

        var graphics = this.graphicsFactory.Create(device);
        try
        {
            // Do something with graphics
        }
        finally
        {
            this.graphicsFactory.Release(graphics);
        }
    }
}

至于选择要使用的设备,可以使用另一个抽象工厂来完成,或者如果经常这样做,您可以使用策略模式 https://stackoverflow.com/questions/1499442/best-way-to-use-structuremap-to-implement-strategy-pattern#1501517在合成时加载所有选项,然后在运行时有选择地选择设备。或者,如果您的设备是一次性的,您可以制定抽象工厂策略或寻求一些更高级的设计模式来清理它们。

您还可以考虑使用适配器模式为 GraphicsInterface 创建一个抽象,如果它还没有一个合适的可以注入(和交换)的具有您所需要的所有成员的抽象。

public interface IGraphicsInterfaceAdapter
{
    // Extract all public properties of GraphicsInteface and define them here.
}

public class GraphicsInterfaceAdapter : IGraphicsInterfaceAdapter
{
    public GraphicsInterfaceAdapter(VideoDevice device, FeatureLevel featureLevel)
        : base(device, featureLevel)
    {
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

未为 DI/IoC 设置 StructureMap 和对象 的相关文章

随机推荐