依赖注入和策略模式策略、模式

2023-09-02 11:58:57 作者:我不要爱情这么残缺

还有就是讨论这个话题了巨大的金额,但每个人似乎都错过一个明显的答案。我想帮助审查这个显而易见的IOC容器解决方案。各种对话承担的策略运行时选择和使用IOC容器。我将继续与这些假设。

There is an enormous amount of discussion on this topic, but everyone seems to miss an obvious answer. I'd like help vetting this "obvious" IOC container solution. The various conversations assume run-time selection of strategies and the use of an IOC container. I will continue with these assumptions.

我也希望添加的假设,即它不是必须选择一个策略。相反,我可能需要检索对象的图,在整个图的节点发现了几个策略。

I also want to add the assumption that it is not a single strategy that must be selected. Rather, I might need to retrieve an object-graph that has several strategies found throughout the nodes of the graph.

我会先迅速勾勒出两种常用提出的解决方案,然后我将present,我希望看到一个IOC容器支持的显而易见的选择。我将使用统一的语法示例,但我的问题是不特定于统一。

I will first quickly outline the two commonly proposed solutions, and then I will present the "obvious" alternative that I'd like to see an IOC container support. I will be using Unity as the example syntax, though my question is not specific to Unity.

该方法要求每一个新的战略有一个绑定手动添加:

This approach requires that every new strategy has a binding manually added:

Container.RegisterType<IDataAccess, DefaultAccessor>();
Container.RegisterType<IDataAccess, AlphaAccessor>("Alpha");
Container.RegisterType<IDataAccess, BetaAccessor>("Beta");

...然后正确的战略是明确要求:

...and then the correct strategy is explicitly requested:

var strategy = Container.Resolve<IDataAccess>("Alpha");

优点:简单,和所有IOC容器的支持 缺点: 通常结合呼叫者IoC容器,当然要求呼叫方知道一些关于策略(如命名为阿尔法)。 在每一个新的战略,必须手动添加到绑定列表。 这种方法不适合处理多种策略中一个对象图。总之,它不符合要求。

Pros: Simple, and supported by all IOC Containers Cons: Typically binds the caller to the IOC Container, and certainly requires the caller to know something about the strategy (such as the name "Alpha"). Every new strategy must be manually added to the list of bindings. This approach is not suitable for handling multiple strategies in an object graph. In short, it does not meet requirements.

为了说明这种方法,假设以下类:

To illustrate this approach, assume the following classes:

public class DataAccessFactory{
    public IDataAccess Create(string strategy){
        return //insert appropriate creation logic here.
    }
    public IDataAccess Create(){
        return //Choose strategy through ambient context, such as thread-local-storage.
    }
}
public class Consumer
{
    public Consumer(DataAccessFactory datafactory)
    {
        //variation #1. Not sufficient to meet requirements.
        var myDataStrategy = datafactory.Create("Alpha");
        //variation #2.  This is sufficient for requirements.
        var myDataStrategy = datafactory.Create();
    }
}

IoC容器则具有以下绑定:

The IOC Container then has the following binding:

Container.RegisterType<DataAccessFactory>();

优点: 在IOC容器是从消费者的隐藏 的环境上下文更接近所希望的结果,但...

Pros: The IOC Container is hidden from consumers The "ambient context" is closer to the desired result but...

在每个策略的构造可能有不同的需求。但是,现在的构造注射的责任已转移到从容器抽象工厂。换句话说,每一个新的策略被添加时间,可能有必要修改相应的抽象工厂。 在大量使用的策略意味着创建抽象工厂的沉重金额。这将是很好,如果IOC容器干脆放弃一个的小的更多帮助。 如果这是一个多线程应用程序和周围语境确实被线程局部存储提供,然后由一个对象被使用一个注入抽象工厂创建它所需要的类型时,也可能是运行在不同的线程它不再具有获得必要的线程本地存储值。 The constructors of each strategy might have different needs. But now the responsibility of constructor injection has been transferred to the abstract factory from the container. In other words, every time a new strategy is added it may be necessary to modify the corresponding abstract factory. Heavy use of strategies means heavy amounts of creating abstract factories. It would be nice if the IOC container simply gave a little more help. If this is a multi-threaded application and the "ambient context" is indeed provided by thread-local-storage, then by the time an object is using an injected abstract-factory to create the type it needs, it may be operating on a different thread which no longer has access to the necessary thread-local-storage value.

这是我想用上述两种方法,而不是方法。它包括提供委托作为IOC容器结合的一部分。最重要的是IOC容器已经有这个能力,但这种具体做法具有重要的细微差别。

This is the approach that I want to use instead of the above two approaches. It involves providing a delegate as part of the IOC container binding. Most all IOC Containers already have this ability, but this specific approach has an important subtle difference.

语法将是这样的:

Container.RegisterType(typeof(IDataAccess),
    new InjectionStrategy((c) =>
    {
        //Access ambient context (pehaps thread-local-storage) to determine
        //the type of the strategy...
        Type selectedStrategy = ...;
        return selectedStrategy;
    })
);

请注意, InjectionFactory 是没有的返回 IDataAccess 的实例。相反,它返回一个类型说明实现 IDataAccess 。 IoC容器然后将执行通常的建立和建立这种类型,其中可能包括被选中的其他策略。

Notice that the InjectionFactory is not returning an instance of IDataAccess. Instead it is returning a type description that implements IDataAccess. The IOC Container would then perform the usual creation and "build up" of that type, which might include other strategies being selected.

这是相较于标准型到委托绑定,在统一的情况下,为codeD这样的:

This is in contrast to the standard type-to-delegate binding which, in the case of Unity, is coded like this:

Container.RegisterType(typeof(IDataAccess),
    new InjectionFactory((c) =>
    {
        //Access ambient context (pehaps thread-local-storage) to determine
        //the type of the strategy...
        IDataAccess instanceOfelectedStrategy = ...;
        return instanceOfelectedStrategy;
    })
);

以上真正接近满足整体需求,但绝对达不到假想的统一 InjectionStrategy

关注第一个样品(其中用一个假设的统一 InjectionStrategy ):

Focusing on the first sample (which used a hypothetical Unity InjectionStrategy):

优点: 隐藏容器 在不需要任何创造无限抽象的工厂,或者有消费者摆弄着他们。 在无需手动调整IOC容器绑定每当一个新的战略是可用的。 允许容器留住生命周期管理控制。 支持纯DI故事,这意味着,一个多线程应用程序可以在与适当的线程局部-存储设置一个线程创建整个对象的曲线图。 Pros: Hides the container No need either to create endless abstract factories, or have consumers fiddle with them. No need to manually adjust IOC container bindings whenever a new strategy is available. Allows the container to retain lifetime management controls. Supports a pure DI story, which means that a multi-threaded app can create the entire object-graph on a thread with the proper thread-local-storage settings. 因为键入的战略返回不可用创建初始的IOC容器绑定的时候,就意味着可能有微小的性能损失首次类型返回。换言之,容器必须在现场反映的类型发现什么构造有,以便它知道如何注入它。该类型的所有后续出现应该是快速的,因为容器可以缓存它发现,从第一次的结果。这绝不是一个骗子值得一提的,但我想充分披露。 ??? Because the Type returned by the strategy was not available when the initial IOC container bindings were created, it means there may be a tiny performance hit the first time that type is returned. In other words, the container must on-the-spot reflect the type to discover what constructors it has, so that it knows how to inject it. All subsequent occurrences of that type should be fast, because the container can cache the results it found from the first time. This is hardly a "con" worth mentioning, but I'm trying for full-disclosure. ???

有一个现有的IOC容器,可以这种方式运行?任何人有实现这种效果的统一定制注塑级?

Is there an existing IOC container that can behave this way? Anyone have a Unity custom injection class that achieves this effect?

推荐答案

据我所知,这个问题是几个候选策略之一,有关运行时选择或映射。

As far as I can tell, this question is about run-time selection or mapping of one of several candidate Strategies.

没有理由依赖于一个DI容器要做到这一点,因为至少有三种方法可以做到这一点的容器中不可知的方式:

There's no reason to rely on a DI Container to do this, as there are at least three ways to do this in a container-agnostic way:

使用一个元数据角色提示 使用一个角色界面角色提示 使用一个部分机型名称的角色提示 Use a Metadata Role Hint Use a Role Interface Role Hint Use a Partial Type Name Role Hint

我个人的preference是部分机型名称的角色提示。

My personal preference is the Partial Type Name Role Hint.

 
精彩推荐
图片推荐