I am making a payment system for my site. Users can select one of several payment providers to pay, but all should behave in the same way. I thought to represent this behavior like this:
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() {
}
}
You are supposed to use this by writing PaymentProvider.AllPaymentProviders["key"].pay(). The idea is that the functions using this class don’t need to know about how the underlying payment provider is implemented, they just need to know the key.
However, at the moment, if you have access to the PaymentProvider class, you also have access to the inheriting classes. Its possible to instantiate a new copy of the inheriting classes, and make use of them in an unexpected way. I want to encapsulate the inheriting classes so that only the abstract PaymentProvider knows about them.
How should I do this? Different protection levels like protected don’t work here – In Java, protected means that only other classes in the namespace can use that class, but in C# it means something else.
Do I have the right idea here? Or should I use a different method?
A couple of options spring to mind:
PaymentProviderclass as private nested classes. You can still separate the source code by makingPaymentProvidera partial class – use one source file per implementationThe first option is likely to be the cleanest if you don’t mind separating the clients from the implementation in terms of assemblies.
Note that both of these are still valid options after the change proposed by Jamiec’s answer – the “visibility” part is somewhat orthogonal to the inheritance part.
(As an aside, I hope the method is really called
Pay()rather thanpay()🙂