While coding at work (Autoscribe), I needed to come up with a cross-cutting observer pattern. When I say 'cross-cutting', I mean that the mechanism had to work with several class types using interfaces.
What was needed, was an easy way to implement the interface in classes that have no base-type, or in classes that already have a base type. It also had to be relatively fool-proof to code with. I decide to present this as a pattern as this looks more imposing than an article entitled 'A Good Trick with Interfaces'.
Although I have presented this technique in C#, it would work just as well in any language that disallows multiple inheritance such as VB.NET and Java.
The 'Internal Implementor' (for want of a better name) is a quick trick to reduce the amount of code required to implement the same interface across classes. It consists of an interface definition, a class that implements the basics of the interface and a procedure to using that class in derived and non-derived classes. A derived class in this case is a class that already inherits from some other base class. The normal approach is to inherit the interface and then either implement the interface again in the derived class or wrap an internal implementation instance al la Visual Basic inheritance.
The pattern consists of the Interface class (
IMyInterface in our example) and an implementation class (
MyInterfaceImpl). The interface consists of two methods:
MyBasicMethod is a method that is the same for all class implementations. This is very simple to code in the
MyInterfaceImpl class. The second method,
MyAbstractMethod, will be implemented differently in each class type. Traditionally, this would be created using the
abstract keyword. However, this means that until the method is implemented, classes cannot be instantiated. Therefore, in this case, we don't use the
abstract keyword. Instead, we implement the
MyAbstractMethod in the
MyInterfaceImpl as a method that simply throws an exception, indicating that this method should be overridden.
This allows us to use the
MyInterfaceImpl class as both a base class (where abstract methods would be valid) and as an internal implementation class (where abstract methods would not be valid).
The example code shows the basic interface:
public interface IMyInterface
MyInterfaceImpl class implements the basic functionality of this interface, allowing our non-derived class to inherit directly from it, overriding the class-specific method:
public class MyNonDerivedClass : Internal.MyInterfaceImpl
MyInterfaceImpl.MyAbstractMethod was truly an abstract method, this would make no difference. However, to enable the same class to be useable as a contained implementation, the
MyInterfaceImpl class uses another technique:
public void MyBasicMethod()
The important point here is that the abstract method is implemented to simply throw an exception. If this was made an abstract method, then you would be unable to instantiate an instance to allow wrapping of this class as a contained implementation, and if the method simply returned without doing anything, the developer might not notice that it had not been overwritten. In this method, an exception would be thrown at runtime if an override is not provided.
The following code shows how the
IMyInterface inheritance and wrapping a contained
MyInterfaceImpl work in the
public class MyDerivedClass : SomeBaseClass, IMyInterface
private Internal.MyInterfaceImpl internalImplementation = null;
The class-specific code for
MyAbstractMethod is implemented explicitly instead of passing the call off to the contained
MyInterfaceImpl class. The
BadDerivedClass does this in the code example to demonstrate the exception being thrown:
This method allows the use of a single class as both an inheritance base and a containment class. Without this technique, two
MyInterfaceImpl-style classes would be required: one that provided an abstract method that required overriding, and another that provided a
NULL method implementation for containment wrapping. I find this pattern is quick to implement in cases where complex framework classes share subsets of functionality.
Pros and Cons
The benefit of abstract methods is that the compiler catches them if they are not overwritten. This pattern does not have compile-time checking, but uses runtime exceptions to do the same job. This is less convenient in the short term as errors are not detected until testing is performed.
On the other hand, this method is simple and reduces the need for two implementation classes, so in the long run (if you have many cross-cutting functionality subsets, or many classes that must share functionality), then the reduced work more than makes up for the lack of compile-time error support.
If you know better than I do about any of this, comments are welcome. There are probably spelling and grammar mistakes in there somewhere, and if you're bored, then feel free to look for them.
I would like to thank my employer, John Boother at Autoscribe for allowing me to write this article based on research performed for my job.
15th April 2004 -- Ooh, look! My second CodeProject article. People might start to think I know what I'm doing.