Provider Model Misconceptions
Paul van Brenk does not understand the Provider Model that is built into .NET 2.0. I don't think a lot of other people really get it either. His argument against using abstract base classes is a common one for anyone that has been doing COM/COM+/C++ development.
For the past 15 or so years, if you wanted to create a pluggable architecture, you used Interfaces. They define a signature that classes must implement in order to conform to that Interface. He says that this is the best way to go, and he is incorrect. I can see where he is coming from though, so let me clear the air a bit. Most of this is taken from my two hour presentation on the Provider Model, which I'll post online sooner or later.
Providers with Interfaces
- Pros
- Straightforward
- No type conversions
- Cons
- Impossible to version
- Hard to maintain
- Does not scale well
- No default implementation
I'm not going to hit on the pros at all, cause that much is obvious. But lets look at the cons. Interfaces are immutable, making versioning them impossible. Once an interface is made public, you can't change it without breaking the contract between classes that the Interface creates. Paul talked about the abstract class way being a maintenance issue... how easy do you think that maintaining 4 different interface versions would be? What about 5 or 6? Do you really want to have to worry about whether you should implement ICoolMethod, ICoolMethod1, or ICoolMethodEx? Finally, you can't have any default implementation, or implementation that every provider should share. All you get is the mold by which all implementing classes should conform to.
Abstract base classes solve all those problems. First of all, that common contract between classes is created through an inheritance chain. This is accomplished by implementing the Strategy design pattern. It's a more OOP architecture. For anyone coming from a VB background, it should fit like a warm glove. Using this method, you'll be able to create a base class, like MembershipProvider, which serves as the "face" of the Strategy pattern. This class not only defines what the rest of the providers will look like (because this class is marked either "abstract" or "MustInherit") but it also defines default functionality that every provider must implement.
This makes life easier for plugin developers in many ways. First, it's much easier to version. You can add functionality at any time to any part of the inheritance chain without breaking any existing code. If you add something to the base of the chain, every part of the chain above that has access to it. Therefore, it allows you to scale functionality up (by adding new capabilities) as well as out (by adding new providers).
Now, Paul was upset because of a percieved need to implement every function, which he says can be eliminated by using Interfaces. This is patently false in just about every aspect of his complaint. First of all, you have to implement every method on an interface, or it won't conform to that interface, and therefore, it won't compile. Second, the functionality issue is easily solved by making your provider default to a certain value (if Integer, 0; if String, then String.Empty; If boolean, then false, etc) for its operations. Then, you only override functionality that CAN be accomplished, thereby saving on the amount of code to write.
Paul suggests that you throw a "NotImplementedException" instead of provifing default "null" values. This is an extremely bad idea. Exceptions are expensive to throw, and expensive to catch. The Provider Model architecture was not designed to be a guide as to what should be an exception and what shouldn't/ You may so choose to throw exceptions in your provider based on certain runtime criteria. But you should not throw an exception if a method is not defined. Instead, your calling code should be able to handle and empty or null return value in act in less runtime-costly ways.
There's a lot more to the architecture than this (remember my presentation was two hours long), so this is about all I'm going to tackle for now. Just remember that, if you're coming from a C/C++/C#/Java/COM/COM+ programming background, this is probably a little Greek to you. But if you understand the underlying reasons for the architecture, it makes a whole lot of sense. And since Microsoft had built this functionality into the base of the Framework, you're going to see a lot more of this architecture.
And be careful. All Provider Models are not created equal.