Refactoring to remove code duplication using the strategy pattern

The strategy pattern‘s main benefit is often stated as being that it provides the ability to essentially swap out parts of an algorithm’s behaviour at runtime. There is another use however that may be deemed overkill and that is simply to get rid of duplicate code.

Consider the following two methods, each with DO A STUFF and DO B STUFF as identical lines of code.

public void foo() {
  // do A stuff
  fooSpecificSection();
  // do B stuff
}
public void bar() {
  // do A stuff
  barSpecificSection();
  // do B stuff
}

How can we refactor the offending abomination to get rid of the duplication? There are a number of techniques, one way is simply to use simple control flow statements (switch, if) as suggested in the following excellent overview of the strategy pattern. So we would have the following for example.

enum Action {FOO, BAR}
public void fooBar(Action action) {
  // do A stuff
  switch(action) {
    case FOO:
      fooSpecificSection();
      break;
    case BAR:
      barSpecificSection();
      break;
    default:
      throw new IllegalArgumentException();
      break;
   }
   // do B stuff
}

As you can see from the above, depending on the number of lines of code in DO A STUFF and DO B STUFF we might not actually have reduced our total lines of code (TLOC) but we would almost certainly have made maintenance easier and less error-prone since our two cited sections of potentially intentionally identical code are no longer duplicated.

If we where to use the strategy pattern to get rid of the duplication in Java 7 we would end up defining a one method interface and an anonymous inner class as has been neatly illustrated here. In the simplest possible case our interface will effectively just be a function pointer, as is shown below.

interface Action {
  void execute();
}
private template(Action action) {
  // do A stuff
  action.execute();
  // do B stuff
}
public void foo() {
  template(new Action() {
    @Override
    public void execute() {
      fooSpecificSection();
    }});
}
public void bar() {
  template(new Action() {
    @Override
    public void execute() {
      barSpecificSection();
    }});
}

Arguably the solution shown directly above is more convoluted, however consider that the main reason for this is because of Java 7’s poor support for function pointers in the foo() and bar() methods.   This may no longer be an issue with Java 8 with the introduction of method references.

Advertisements