StructureMap and objects not setup for DI/IoC

女生的网名这么多〃 提交于 2019-12-02 06:26:06
NightOwl888

Whenever you are scratching your head trying to work out how to create instances at runtime, you need to step back and look for a design pattern that will fit the problem. DI is meant for composing applications, but controlling runtime behavior should be part of the application design - that is, the part that runs after the application is composed.

In this particular case, Abstract Factory would be a good fit. It allows you to separate the composed services (those injected through the constructor) from runtime services (those passed as method parameters).

However, you should restrict a factory to doing exactly one thing - creating the runtime instance. All other work should be part of other services. This gives you a clean way to inject a runtime object into your service and still allow the service behavior to be tested independently of this step.

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();
    }
}

Your factory can then be supplied to a service during application composition, and runtime instances of GraphicsInterface can be created at runtime. As per your requirement, this can easily be done in multiple spots by injecting it into the constructors of multiple services.

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

As for selecting the device to use, that could either be done with another Abstract Factory, or if it is something that is done often, you could use a Strategy Pattern to load all of the options at composition time, and then selectively choose the device at runtime. Or, if your devices are disposable, you could make a Strategy of Abstract Factories or look to some more advanced design pattern to clean them up.

You might also consider using an adapter pattern to create an abstraction for GraphicsInterface if it doesn't already have a suitable that can be injected (and swapped) that has all of the members you are after.

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)
    {
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!