Quickshiftin - Clever Crazy Code

Template method pattern in BASH

January 27th, 2014

Lately I’ve been writing my fair share of BASH, and slowly becoming proficient with it. I wanted to share my version of implementing a common design pattern from the Object Oriented world in BASH. Namely, the template method design pattern.

Quick Review

Just to review or introduce folks who’ve not seen it yet, I like the definition from the Head First Design Patterns book. “The Template Method defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.” You really don’t need classes to implement a template method, though you do get a little more sugar in the OOP world to play with. Let’s take a quick peak at a simple example with classes for illustration. I’m using PHP for demonstration, but the example is so trivial, I’m sure you could envision it in your favorite OO language. A common template method use case is to provide for pre and post operations. Take a look at Ruby on Rails Filters for a real world example.

abstract class BaseTemplateMethod
{
    public function templateMethod
    {
        $this->requiredStep();

        // Do standard stuff

        $this->optionalStep();
    }

    abstract protected function requiredStep();

    protected function optionalStep() {}
}

When defining a template method, you can make the points where external code is called optional or required. Generally the optional methods are referred to as hook methods. Given the former class, BaseTemplateMethod, a subclass needs to implement a requiredStep method (or itself be abstract and defer to yet another class for an implementation). The subclass doesn’t need to define an optionalStep method, because if it doesn’t, the base class will call its implementation which does nothing. This is actually a trivial use of the Null Object or Null method design pattern. If the subclass overrides the optionalStep method, then the base class will use the implementation from the subclass. Nice and easy right?

This post isn’t supposed to be a thorough explanation of Template Method, so feel free to ask questions in comments or Google around a bit for explanations. What I really want to show you is how to pull this off in BASH.

BASH Implementation

Classes provide a simple way of being able to refer to other methods, but there are plenty of other ways, depending on the language you’re using. In PHP prior to 5.3, the only real way to do this was the psuedo-type callback. Since PHP 5.4 and in other languages like Javascript, Python, Ruby etc, etc, functions are first class citizens, which means a variable can basically be a function that can then be called. Very much like a base class in an OO implementation saying, “I want to call a particular method from a subclass”, callbacks can be supplied in their stead. In both cases you roughly have some way to call a function that you haven’t implemented during the course of the template method’s execution.

BASH has a mechanism very similar to the old psuedo-type in PHP. Imagine a simple template_method function and a callback as so

function template_method
{
    echo 'About to call another function'
    $1
}

function callback_method
{
    echo "I'm a callback"
}

You can store the name of the callback in a variable, then pass it to the template method like this

callback=callback_method
template_method $callback

The output of which is

About to call another function
I'm a callback

So what about requiring callbacks, allowing them to be optional, or even knowing they’re actually functions in BASH? I found a bit of code on Stackoverflow which I adapted slightly, have a look.

#--------------------------------------------------------------------------------
# Determine if an argument is a function. Taken from this SO thread:
# http://stackoverflow.com/questions/85880/determine-if-a-function-exists-in-bash
#
# Return type of 0 indicates argument is a function, return type of 1 indicates
# argument is not a function.
#--------------------------------------------------------------------------------
function function_exists
{
    [ $(type -t "$1")"" == 'function' ]
}

Now you can write somewhat more robust code like this

function template_method
{
    # Required step
    function_exists "$1"
    if [ $? -gt 0 ]; then
        return 1
    fi

    # Do standard stuff

    # Optional step
    if [ ! -z "$2" ]; then
        function_exists "$2"
        if [ $? -eq 0 ]; then
            "$2"
        fi
    fi
}

That kind of resembles our earlier example from PHP no? Not quite as pretty as an OO implementation, but definitely a viable option.

Summary

If you’re not familiar with template method or callbacks, read through some of the sources I’ve linked to in this article. If you know of these tools and find yourself looking for an option in BASH, then look no further! I’ve found this simple mechanism very useful to reduce conditional logic and make my BASH code loosely coupled. Hopefully you’ve gained more confidence in BASH as a language and see that design patterns can be implemented in procedural languages too.

Share

If you enjoyed this post please consider sharing it!

  • Twitter
  • LinkedIn
  • Facebook
  • Reddit
  • Digg

Leave a Response