Friday, November 27, 2009

The Strong Type Inheritance Pattern

Generics were originally designed to help avoid very common mistakes while coding with various simple structures. The classic examples for this are Lists and HashMaps.
Employing these objects would result in confusion in the best case, and abuse in the form of multi-type elements in the worst case.
Generics are a an elegant solution for this problem - A Simple List<MyClass> makes a world of difference in both readability and usability of the code. It will save you both a cast and the occasional ClassCastException.

So what else are generics good for?
I think they open up new and interesting design patterns, one of may favorites is the Strong Type Inheritance Pattern (i am unaware of a different name for it).

The Strong Type Inheritance pattern is a simple pattern that allows you to make use of an inheriting type's "Type" to create typesafe methods that would otherwise require more complex, less efficient and more error prone reflection.

The example below shows a simple serializer class that provides serialization to inheriting types in a typesafe way. it also uses the type name as the file name.


/// <summary>
/// This is a save/load from xml facility.
/// it uses the class type as the file name,
/// and so can only persist a single instance of each type.
/// </summary>
/// <typeparam name="InheritingType">
/// The type of a class inheriting from this base class
/// </typeparam>
public abstract class SelfSerializingBase<InheritingType>
where InheritingType : SelfSerializingBase<InheritingType>
{
/// <summary>
/// Load the inheriting type from an xml,
/// use the type name as the file name
/// </summary>
/// <returns></returns>
public static InheritingType LoadFromXml()
{
//create a serializer for the inheriting type
XmlSerializer serializer =
new XmlSerializer(typeof(InheritingType));
//get a stream to load from
FileStream stream =
new FileStream(typeof(InheritingType).Name, FileMode.Open);
//deserialize and return the result
return (InheritingType)serializer.Deserialize(stream);
}
/// <summary>
/// Save the current instance to an xml.
/// Use the type name as the file name.
/// </summary>
public void Save()
{
//create a serializer for the inheriting type
XmlSerializer serializer =
new XmlSerializer(typeof(InheritingType));
//create a new file
FileStream stream =
new FileStream(typeof(InheritingType).Name, FileMode.CreateNew);
//serialize ourselves to the file.
serializer.Serialize(stream, this);
}
}

/// <summary>
/// A freeloading child that gets everything for free
/// and doesn't do anything itself.
/// The code for the child is even shorter than our summery!
/// :)
/// </summary>
public class SerializingChild : SelfSerializingBase<SerializingChild>
{
public int SomeProperty { get; set; }
}

static class TestClass
{
/// <summary>
/// An example of how we would use the methods from the parent.
/// </summary>
public static void TestSerialization()
{
//create an instance
SerializingChild child = new SerializingChild();
//set our property
child.SomeProperty = 10;
//serialize the instance
child.Save();
//load the instance
child = SerializingChild.LoadFromXml();

}
}


Lets examine the base class definitions, which is what this pattern is all about:



public abstract class SelfSerializingBase<InheritingType>
where InheritingType : SelfSerializingBase<InheritingType>



So what we have is a base class that has a seemingly cyclic definition.
It expects a generic type , and it also expects this generic type to be an extender of itself.
The intention here is to say that inheriting types should pass their own type if they wish to use use these facilities.
An important part of this pattern is the limiting "where" clause that requires any type that wishes to use this base class to use a child which inherits from this base class. This limit is not required by the functionality - this class could easily have been a "serializer" facility that provides a load/save functionality, but in our design we wish to mandate that ONLY inheriting types are allowed to have access to this functionality.
The Generic magic here is that we get a static method of any extending type which is type-safe and implemented just one.

Ok, so we can use the type of an inheriting class and we force this type to inherit from the base - but what is it really good for?
A good example for using this pattern is in castle's ActiveRecord. ActiveRecord provides various database access facilities to inheriting classes, it is effectively a thin wrapper across NHibernate's functionality ( - in this implementation, ActiveRecord itself is an interesting and useful pattern for persistent objects).
This is only a partial example however, because castle's ActiveRecord source code does not include the "where" clause, which should be a part of the pattern - since the purpose of the clause is to inform (and force) the developer using this class that the intention of the framework is that you extend this class.
If a developer misunderstands the design of a base class implementing a Strong Type Inheritance they will get a complier error and hopefully read the documentation and change their implementation to comply with the intended design.

One important point we must pay attention to when we use this pattern is that the generic type is expected to be the FINAL type of the entity, if we wish to extend the base class with another class that adds functionality but is still abstract - we must add the same InheritingType to its class signature. once we set an actual type to the generic definition, we sealed all future generations from using the base class's generic facilities.
For example - if we happen to extend SerializingChild with say YetAnotherChild, we are exposing a "save" method that can only save the components of a SerializingChild. This is a strange an unexpected behavior for a developer using YetAnotherChild and will likely lead to abuse and inevitably to increased cost of maintenance.