c# - 运行时的条件依赖解析器(.net Core)
问题描述
我有两个类PaymentGatewayFoo
,PaymentGatewayBoo
它们都实现了一个通用接口IPaymentGateway
:
interface IPaymentGateway { }
class PaymentGatewayFoo : IPaymentGateway { }
class PaymentGatewayBoo : IPaymentGateway { }
客户端请求有一个标识符,该标识符决定使用哪个实现:
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();
}
}
如何根据客户在运行时的请求解决正确的实现?
这个问题不是重复的,它是相似的,但它是关于两个独立的控制器(即使答案表明代码甚至不需要条件依赖注入),在我的情况下,基于客户端属性的运行时需要条件依赖价值。
解决方案
这里有几个选项,但对我来说最明显的两个是使用工厂模式或适配器模式。
1.使用工厂
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
.
2.使用适配器
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();
}
}
优点和缺点:
- 这样做的好处是客户端只需要知道一个抽象。
替代实现
正如您所注意到的,在我的工厂和适配器中,实现是直接注入的。甚至不是通过它们的抽象,而是通过它们的具体类型。这可能看起来很奇怪,但只要适配器和工厂是应用程序入口点的一部分(也就是Composition Root),这样做就完全没问题。
但是可以使用其他更动态的选项,例如:
- 注入
Func<PaymentType, IPaymentGateway>
委托以解析类型。 - 注入一个
Dictionary<PaymentType, IPaymentGateway>
. - 注入一组 IPaymentGateway 实现。
- 注入容器本身
- 正如 Armand 建议的那样,使用动态过滤,但请注意,这会导致您将
Identifier
属性添加到界面中,它仅出于技术原因而存在。没有消费者(除了适配器或工厂)对此标识符感兴趣。因此,它不属于接口。更好的解决方案是在组合根中解决此问题,例如,可能通过使用属性标记实现。
推荐阅读
- angular - 角度库安装对等依赖问题
- python - 如何找到一个独特的 HTML 元素?
- java - 任务':app:kaptDemoProductionDebugKotlin'的错误执行失败。?
- sql - 如何对零进行此操作?
- java - jar 文件中的 Geckodriver
- spring-boot - 如何将页面的内容作为列表获取
而不是列表 在 Kotlin 中使用 RestTemplate - mysql - 如何为在 docker 容器上运行的 MySQL 设置对本地文件系统上文件的访问权限
- javascript - 反应忽略 .prettierignore 文件 [编辑:与更漂亮无关]
- http - 设置 GeoServer JNDI
- airflow - Apache 气流 DAG 任务状态 - web api