Friday, September 4, 2009

Building a Wishlist Service: Template Method

When I'm giving an interview, one of my favorite questions is “Are you familiar with Design Patterns? Please describe your favorite pattern, tell me why you like it, and give an example where you've recently used it.” Historically, if I were to be asked that question, my answer would be Strategy; currently, I think it would be Template Method. Which is interesting, because those two patterns basically do the same thing from different directions.

A description first: Template Method is a pattern for building class hierarchies in which the base class of the hierarchy imposes logic on its subclasses. The base class defines public methods, then calls into abstract protected methods that must be implemented by the subclass. For example, the base class might define a validate() method:

public final void validate()

Historically I've liked Template Method because it avoids bugs caused by subclasses that don't invoke their super's implementation of a method (I take the attitude that “subclasses are like ogres,” which is a topic for a future post). However, as I'm realizing with this service, it also highlights duplicated code, and allows that code to be moved into the superclass. In this example, there's only one method that's actually implemented by the subclass (and its name should make it obvious).

I think it also pushes you toward moving responsibilities out of the class hierarchy entirely. In this example, validateRequiredParams() was originally intended for the subclass, which knew what parameters it needed. But the actual validation code was common to all subclasses, so I changed the method to simply ask the subclass for a list of its required parameters. A little more thought, and I realized that this isn't really an attribute of the subclass, but of the operation itself. So I added the list of parameters to the enum defining the service's operations (and this spurred writing an article for my website):

public enum Operation
    // only the third example has a required parameter

    RetrieveList(HttpMethod.GET, null),
    AddItem(HttpMethod.POST, ProductEntry.class),
    DeleteItem(HttpMethod.POST, null, RequestParameter.itemId),
    // ,,,

This kind of thinking, taken to an extreme, will take you out of Template Method and into objects constructed according to a configuration file. And that's not a bad thing: if your subclasses don't have behavior, they don't deserve to exist.

No comments: