只让抽象类知道它的继承者

时间:2012-01-16 11:49:28

标签: c# asp.net

我正在为我的网站制作支付系统。用户可以选择多个支付提供商中的一个进行支付,但所有支付提供商都应该以相同的方式行事。我想这样表示这种行为:

public abstract class PaymentProvider {
    private static var methods = Dictionary<String,PaymentProvider>
    {
        {"paypal",new PaymentProviderPaypal()},
        {"worldpay",new PaymentProviderWorldpay()}
    }

    public static Dictionary<String,PaymentProvider> AllPaymentProviders
    {
        get {return methods;}
    }

    public abstract pay();
}

public class PaymentProviderPaypal : PaymentProvider {
    public override pay() {

    }
}

public class PaymentProviderWorldpay : PaymentProvider {
    public override pay() {

    }
}

你应该通过写PaymentProvider.AllPaymentProviders["key"].pay()来使用它。这个想法是使用这个类的功能不需要知道底层支付提供商是如何实现的,他们只需要知道密钥。

但是,目前,如果您可以访问PaymentProvider类,则还可以访问继承类。它可以实例化继承类的新副本,并以意想不到的方式使用它们。我想封装继承类,以便只有抽象PaymentProvider知道它们。

我该怎么做?像protected这样的不同保护级别在这里不起作用 - 在Java中,protected意味着命名空间中只有其他类可以使用该类,但在C#中它意味着其他类。

我在这里有正确的想法吗?或者我应该使用不同的方法吗?

2 个答案:

答案 0 :(得分:3)

我想到了几个选择:

  • 将其放在与客户端代码不同的程序集中,并使实现抽象
  • 将实现放在PaymentProvider类中作为私有嵌套类。您仍然可以通过使PaymentProvider成为部分类来分离源代码 - 每个实现使用一个源文件

如果你不介意在程序集方面将客户端与实现分开,那么第一个选项可能是最干净的。

请注意,在Jamiec的回答提出更改后,这两个选项仍然是有效选项 - “可见性”部分与继承部分有些正交。

(顺便说一句,我希望这个方法真的叫Pay()而不是pay():)

答案 1 :(得分:2)

你的继承heirachy有点不稳定,我很想做一个类似但又截然不同的方式。

public interface IPaymentProvider
{
  void Pay()
}

// Implementations of IPaymentProvider for PaypalPaymentProvider & WorldpayPaymentProvider

public static class PaymentHelper
{
    private static var providers = Dictionary<String,IPaymentProvider>
    {
        {"paypal",new PaymentProviderPaypal()},
        {"worldpay",new PaymentProviderWorldpay()}
    }


    public static void Pay(string provider)
    {
        if(!providers.Containskey(provider))
            throw new InvalidOperationException("Invalid provider: " + provider);

        providers[provider].Pay();
    }

}

然后用法就像PaymentHelper.Pay("paypal")

显然,如果有更多数据要提供给Pay方法,则可以将其添加到接口和帮助程序中。例如:

public interface IPaymentProvider
{
  void Pay(double amount);
}

public static void Pay(string provider, double amount)
{
    if(!providers.Containskey(provider))
        throw new InvalidOperationException("Invalid provider: " + provider);

    providers[provider].Pay(amount);
}