Introduction
Design Patterns have been one of the main topics in software engineering since the book "Design Patterns: Elements of Reusable Object-Oriented Software" (1995). After that, there have been other books on these "GOF-Patterns", like the top rated "Head First Design Patterns". Most of the patterns are still valid, but some of them have become a bit useless to be practiced in the Microsoft .NET environment. One example is the Iterator-pattern (for handling managed collections) because of .NET 2.0 Generics.
The book Head First Design Patterns describes the Template Method Design Pattern as follows:
"Template Method - Defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure."
Basically, this is close to the idea of functional programming, lambda expressions, function pointers, (/functors), etc. (despite that the approach has typically been mathematical). What if we could have a template function and give it functions as parameters? Well, in Microsoft .NET 3.5, we can, so there is alternative way to make the same thing as the Template Method Design Pattern.
Template Method Design Pattern in practice
OK, as if we would like to have a software for... let's say... a recipe-making software for hot drinks. There are some generic methods like:
- Boil water
- Brew
- Pour in cup
- Add condiments
So, let that be the generic template algorithm. First, what we need is a unit test. VS2008 unit tests are easy to generate and great for debugging. Let the test be something simple like this:
[TestMethod()]
public void HotDrinkTest1()
{
List<string> recipe = new List<string>();
Coffee myCoffee = new Coffee();
recipe.Add("Making coffee...");
recipe.AddRange(myCoffee.MakeRecipe());
Tea myTea = new Tea();
recipe.Add("Making tea...");
recipe.AddRange(myTea.MakeRecipe());
recipe.ForEach(s => Console.WriteLine(s));
}
and we would like it to make a recipe like this:
- "Making coffee...",
- "Boiling water" (from template),
- "Dripping coffee through filter",
- "Pouring into cup" (from template),
- "Adding sugar".
and:
- "Making tea...",
- "Boiling water" (from template),
- "Steeping the tea",
- "Pouring into cup" (from template),
- "Adding lemon".
Now, the "schoolbook"-solution using the Template Method Design Pattern will look like this:
where custom hot drinks (like Coffee, Tea, etc.) override the needed special functionality from the template algorithm class (abstract class called HotDrink
). The source code will look like this:
public abstract class HotDrink {
public List<string> MakeRecipe() {
List<string> recipe = new List<string>();
recipe.Add(BoilWater());
recipe.Add(Brew());
recipe.Add(PourInCup());
recipe.Add(AddCondiments());
return recipe;
}
public abstract string Brew();
public abstract string AddCondiments();
public string BoilWater() {
return "Boiling water";
}
public string PourInCup() {
return "Pouring into cup";
}
}
public class Tea : HotDrink {
public override string Brew() {
return "Steeping the tea";
}
public override string AddCondiments() {
return "Adding Lemon";
}
}
public class Coffee : HotDrink {
public override string Brew() {
return "Dripping Coffee through filter";
}
public override string AddCondiments() {
return "Adding Sugar";
}
}
That was easy. This is another version of the current class diagram:
Lambda Expression
So, what's wrong with Template Methods? Well, one of the generally accepted fundamental principles of Object-Oriented design is "Favor Composition Over Inheritance". If the HotDrink
class changes, there will be trouble as this was not the most dynamical way. A better design would look something like this:
But, this will add more complexity. Could we keep the number of classes and lines of code low? Let's try another solution, with Microsoft .NET 3.5 Framework's new functional programming... We already have the unit test, and it can be exactly the same as in the Template Method Design Pattern unit test! Let's see the template algorithm, the class HotDrink
: it will also look much the same, only there are now parameters for custom functions, and the (abstract class) inheritance is left away:
public class HotDrink {
public List<string> MakeRecipe(List<Func<string>> CustomMethods) {
List<string> recipe = new List<string>();
recipe.Add(BoilWater());
recipe.Add(CustomMethods[0]());
recipe.Add(PourInCup());
recipe.Add(CustomMethods[1]());
return recipe;
}
public string BoilWater() {
return "Boiling water";
}
public string PourInCup() {
return "Pouring into cup";
}
OK... And now, explanation for what is List<Func<string>>
. It's just a list of functions... :-) Func<string>
means a code that we can execute at runtime, and the return type for the function is string
.
If it would also have input parameters, they would come before the result, so the syntax would be Func<T, T2>
, where T
would be some input type and T2
some return type.
Then those special drinks:
public class Tea {
public List<string> MakeRecipe() {
List<Func<string>> CustomMethods = new List<Func<string>>(){
(() => "Steeping the tea"),
(() => "Adding Lemon")
};
return (new HotDrink()).MakeRecipe(CustomMethods);
}
}
public class Coffee {
public List<string> MakeRecipe() {
List<Func<string>> CustomMethods = new List<Func<string>>(){
(() => "Dripping Coffee through filter"),
(() => "Adding Sugar")
};
return (new HotDrink()).MakeRecipe(CustomMethods);
}
}
And that's it. The syntax of List<...>{ ..., ..., ...}
is also a new Microsoft .NET 3.5 enhancement called Collection Initializer, just an easier way to fill the list. The syntax (() => ""
) is a lambda expression, and means the same as the anonymous function delegate(){return "...";}
, which is like a normal function, just typed inline. If the method would have much more functionality than just return
, then it would be clearer to use a (named) delegate. Anonymous delegates won't be visible in the class diagram:
One more thing. I drew the interface to the picture, but left it temporarily out of here for the similarity. Of course, it is always important to use classes through interfaces, and not use straight concrete classes, so here you go:
public interface IHotDrink{
List<string> MakeRecipe();
}
and that is also in use in the source code included with this article.
How about performance?
I used Visual Studio 2008 Beta 2 in Microsoft Virtual PC 2007, so I can't do any reliable performance tests. However, I ran the unit test case over many times, and the performance seemed to be quite equal:
So what's the difference?
- Possibilities to extend more, uses composition, not inheritance.
- Lighter to implement as sometimes those
Func<>
s can be used straight from the code and those Tea
and Coffee
classes are useless. - C# developers are not used to reading the new enhancements yet. The code is harder to read.
- Also, harder to get the big picture, because current graphical tools are for Object-Oriented design, not for functional programming.
Let's see if Functional Programming is the way of the future. The real best practices always come after some time has passed.
History
- 2007-11-07: The first version and my first article. :-)