I've written about the template method pattern before. For my money it's still a very useful pattern for building super lightweight frameworks and enabling the open-closed principle which states:
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
So let's review quickly what a template method looks like and what it can do for our code:
public abstract class PriceCalculator
{
public Money Calculate(Product product)
{
Money retailPrice = GetRetailPrice();
Discount discount = CalculateDiscount(product);
return discount.Apply(retailPrice);
}
public abstract Discount CalculateDiscount(Product product);
public Rate GetRetailPrice() { //... }
}
public class GoldCustomerPriceCalculator : PriceCalculator
{
public override Discount CalculateDiscount(Product product)
{
// Gold customers get 20% off, OR
// We could use per-product discounts.
return new Discount(20);
}
}
public class StandardCustomerPriceCalculator : PriceCalculator
{
public override Discount CalculateDiscount(Product product)
{
// Standard customers receive no discount
return new Discount(0);
}
}
It's pretty easy to see we've gotten some variation. This is a simple example off the top of my head and there's probably a better way to tackle this domain problem, but it shows template method in action so I'll leave it alone.
This is all well and good, but what if we encountered a scenario where our class could function autonomously but we want to provide an hook or extensibility point for edge cases or later extension (beware of YAGNI on the latter). I'll call this technique a hook method.
What's a hook method? By playing with the physics of template method a bit to we can make derivations elective by lifting the abstract constraint on our base class and making the template method virtual. The former move is optional and the later is required. Your solution will dictate whether or not the base class should or should not be declared abstract.
Let's consider an example where we want a start/finish semantic for an implementation of model view presenter. In this example I want to have a base presenter that provides some common functionality: attaching the presenter to the view and raising events to signify the presenter has been started. I want to provide a hook so my presenter implementations can do some processing, call services, obtain reference data, etc. I can accomplish this with a hook method style of template method like so:
public abstract class Presenter : IPresenter
{
public void Start()
{
if (Starting != null) Starting(this, EventArgs.Empty);
View.Attach(this);
Startup();
if (Started != null) Started(this, EventArgs.Empty);
}
protected virtual void Startup() {};
public event EventHandler Starting;
public event EventHandler Started;
}
Or we can return to the contrived example of the price calculator to illustrate a non-abstract class:
public class PriceCalculator
{
public Money Calculate(Product product)
{
Money retailPrice = GetRetailPrice();
Discount discount = CalculateDiscount(product);
return discount.Apply(retailPrice);
}
public virtual Discount CalculateDiscount(Product product)
{
return new Discount(0);
}
public Rate GetRetailPrice() { //... }
}
public class GoldCustomerPriceCalculator : PriceCalculator
{
public override Discount CalculateDiscount(Product product)
{
// Gold customers get 20% off, OR
// We could use per-product discounts.
return new Discount(20);
}
}
Money price = new PriceCalculator.Calculate(someProduct);
// or
Money price = new GoldCutomerPriceCalculator.Calculate(someProduct);
I'm sure many of you have seen examples of this in the wild. I'd file this under "pattern life hack." That is, a simple and subtle shift in thinking around template method that expands its many uses in DRYing up your codebase.