如何使用依赖注入 C# 有条件地选择策略模式的具体实现

问题描述 投票:0回答:3

我正在尝试理解策略模式,以便将其用于解决我遇到的问题。

当前的代码看起来是这样的,我有一个想要根据付款类型处理的金额。

public class PaymentProcessor {
    private PaymentType paymentType;

    public void processPayment(double amount) {
        if (paymentType == PaymentType.CREDIT_CARD) {
            Console.Writeline("Processing credit card payment of amount " + amount);
        } else if (paymentType == PaymentType.DEBIT_CARD) {
            Console.Writeline("Processing debit card payment of amount " + amount);
        } else if (paymentType == PaymentType.PAYPAL) {
            Console.Writeline("Processing PayPal payment of amount " + amount);
        } else {
            throw Exception();
        }
    }

    public void setPaymentType(PaymentType paymentType) {
        this.paymentType = paymentType;
    }
}

enum PaymentType {
    CREDIT_CARD,
    DEBIT_CARD,
    PAYPAL
}

因此,根据策略模式,我需要为所有付款创建一个接口

public interface IPaymentStrategy {
    void processPayment(double amount);
}

然后我需要为每个类创建具体的实现,我只会给出一个例子,但你明白了。

public class CreditCardPaymentStrategy :  IPaymentStrategy {
    public void processPayment(double amount) {
        Console.Writeline("Processing credit card payment of amount " + amount);
    }
}

所以所有的支付策略都会有像上面这样的具体实现。

最后使用依赖注入和依赖反转我将支付处理器重构为如下所示

public class PaymentProcessor {
    private PaymentStrategy paymentStrategy;

    public PaymentProcessor(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void processPayment(double amount) {
        paymentStrategy.processPayment(amount);
    }
}

但这就是我所缺少的。我在哪里以及如何实现条件逻辑来选择正确的具体实现来根据支付类型注册支付策略?

我尝试过在网上查找。我看到的所有示例似乎都有另一个类,例如工厂,它更新具体版本并将其传递到接口中。但我不确定这是正确的方法,因为我觉得我不应该更新不是 POCOS 的类,因为我的 DI 容器应该这样做。那么,根据付款类型有条件地选择具体类型的策略中我缺少什么?我在这里是否使用了正确的模式,因为我看到人们将策略模式与依赖注入进行比较。如果是这种情况,哪种模式更适合条件选择,而不是使用接口注册具体类,并且每次我想使用不同的支付策略时都必须在注册中手动更改它,但能够在运行时在策略之间切换?

c# design-patterns inversion-of-control strategy-pattern
3个回答
0
投票

请参阅 .NET 8 中 MS 文档上的 .NET 文档,您可以使用 Keyed 服务提供程序并使用它正确实现您的服务。 您可以在这里查看更多相关信息:密钥服务

builder.Services.AddKeyedSingleton<IMemoryCache, BigCache>("big");
builder.Services.AddKeyedSingleton<IMemoryCache, SmallCache>("small");


class SmallCacheConsumer(IKeyedServiceProvider keyedServiceProvider)
{
    public object? GetData() => keyedServiceProvider.GetRequiredKeyedService<IMemoryCache>("small");
}

0
投票

在您的第一堂课中,您通过单独的方法设置付款类型。这个方法可以随时调用。在第二个类中,您通过构造函数设置付款类型。课程创建后,您将无法再更改付款方式。

因此,你的两个类并不等同。您可以更改您的第二个课程,使其与您的第一个课程相同:

public class PaymentProcessor {
    private IPaymentStrategy paymentStrategy;

   public void setPaymentType(IPaymentStrategy paymentType) {
        this.paymentType = paymentType;
    }

    public void processPayment(double amount) {
        if(paymentStrategy == null)
        {
           throw InvalidOperationException("call SetPaymentType first!");
        }
        paymentStrategy.processPayment(amount);
    }
}

请注意,这种方法不是线程安全的(如果您想从不同线程使用该类)。


0
投票
container.AddSingletonWithKey<IPaymentStrategy>(PaymentType.CREDIT_CARD, sp=> ...);
container.AddSingletonWithKey<IPaymentStrategy>(PaymentType.DEBIT_CARD, sp=> ...);
container.AddSingletonWithKey<IPaymentStrategy>(PaymentType.PAYPAL, sp=> ...);

然后你可以像这样使用它:

container.GetWithKey<IPaymentStrategy>(PaymentType.PAYPAL).processPayment(amount);

是否创建链接所有这些依赖项的类,或者直接从容器访问它取决于您。

© www.soinside.com 2019 - 2024. All rights reserved.