运行时的条件依赖解析器 (.net Core) [英] Conditional dependency resolver on run-time (.net Core)

查看:37
本文介绍了运行时的条件依赖解析器 (.net Core)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个类PaymentGatewayFooPaymentGatewayBoo,它们都实现了一个IPaymentGateway的通用接口:

I have two classes PaymentGatewayFoo, PaymentGatewayBoo that both implements a common interface of IPaymentGateway:

interface IPaymentGateway { }

class PaymentGatewayFoo : IPaymentGateway { }
class PaymentGatewayBoo : IPaymentGateway { }

客户端请求有一个标识符来决定使用哪个实现:

The client side request has an identifier who's response to determine which implementation to use:

public class OrderService
{
    private readonly IPaymentGateway _service;

    public void DoOrder(bool isFoo)
    {
        if (isFoo)
            //this._service should be resolved with PaymentGatewayFoo
        else
            //this._service should be resolved with PaymentGatewayBoo

        this._service.Pay();
    }
}

如何根据客户端在运行时的请求来解决正确的实现?

How do I resolve the proper implementation based on the client's request on run-time?

这个问题不是重复的,它是相似的,但它是关于两个独立的控制器(即使答案表明代码甚至不需要条件依赖注入),在我的情况下,基于客户端属性值的运行时需要条件依赖.

This question is not duplicate, its similar but its about two separate controllers (Even the answers suggested that the code didn't even needed the conditional dependency injection), in my case the conditional dependency is needed on run-time based on a client property value.

推荐答案

这里有几个选项,但对我来说最明显的两个是使用工厂模式或适配器模式.

There are several options here, but the two that to me are the most obvious are using a factory or the adapter pattern.

public class OrderService
{
    private readonly IPaymentGatewayFactory _factory;

    public void DoOrder(bool isFoo)
    {
        IPaymentGateway service = _factory.Create(isFoo);
        this._service.Pay();
    }
}

工厂在哪里:

public class PaymentGatewayFactory : IPaymentGatewayFactory 
{
    public PaymentGatewayFactory(PaymentGatewayFoo foo, PaymentGatewayBoo boo) {...}

    public IPaymentGateway Create(bool isFoo) =>
        isFoo ? this.foo : this.boo;
}

优缺点:

  • 使用工厂的缺点 是消费者需要了解两个抽象:工厂和 IPaymentGateway.
  • Pros and cons:

    • Downside of using a factory is that the consumer needs to be aware of two abstractions: the factory and the IPaymentGateway.
    • public class OrderService
      {
          private readonly IPayment _payment;
      
          public void DoOrder(bool isFoo)
          {
              _payment.Pay(isFoo);
          }
      }
      

      适配器的位置:

      public class PaymentAdapter : IPayment
      {
          public PaymentAdapter(PaymentGatewayFoo foo, PaymentGatewayBoo boo) {...}
      
          public void Pay(bool isFoo)
          {
              var service = isFoo ? this.foo : this.boo;
      
              service.Pay();
          }
      }
      

      优缺点:

      • 这样做的好处是客户端只需要知道一个抽象.
      • 如您所见,在我的工厂和适配器中,实现是直接注入的.甚至不是通过它们的抽象,而是通过它们的具体类型.这可能看起来很奇怪,但只要适配器和工厂是应用程序入口点的一部分(又名 组合根).

        As you noticed, in my factory and adapter, the implementations are injected directly. Not even by their abstractions, but by their concrete types. This might seem strange, but doing so is completely fine as long as the adapter and factory are part of the application's entry point (a.k.a. the Composition Root).

        但是可以使用其他更动态的选项,例如:

        But other, more dynamic options can be used, such as:

        • 注入 Func 委托来解析类型.
        • 注入Dictionary.
        • 注入一组 IPaymentGateway 实现.
        • 注入容器本身
        • 使用动态过滤,正如 Armand 建议的那样,但请注意,这会导致您将 Identifier 属性添加到界面中,该属性仅出于技术原因存在.没有消费者(适配器或工厂除外)对此标识符感兴趣.因此,它不属于接口.更好的解决方案是在 Composition Root 中解决这个问题,例如,可能通过使用属性标记实现.
        • Injecting a Func<PaymentType, IPaymentGateway> delegate to resolve the types.
        • Injecting a Dictionary<PaymentType, IPaymentGateway>.
        • Injecting a collection of IPaymentGateway implementations.
        • Injecting the container itself
        • Using dynamic filtering, as Armand suggests, but do note that is causes you to add the Identifier property to the interface, where it only exists for technical reasons. No consumer (other than the adapter or the factory) is interested in this identifier. It, therefore, doesn't belong to the interface. A better solution is to solve this problem in the Composition Root, possibly by marking the implementations with an attribute, for instance.

        这篇关于运行时的条件依赖解析器 (.net Core)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆