Design patterns Strategy Pattern Hiding strategy implementation details

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Insert
> Step 2: And Like the video. BONUS: You can also share it!

Example

A very common guideline in object oriented design is "as little as possible but as much as necessary". This also applies to the strategy pattern: It is usually advisable to hide implementation details, for example which classes actually implement strategies.

For simple strategies which do not depend on external parameters, the most common approach is to make the implementing class itself private (nested classes) or package-private and exposing an instance through a static field of a public class:

public class Animal {

  private static class AgeComparator implements Comparator<Animal> {
    public int compare(Animal a, Animal b) {
      return a.age() - b.age();
    }
  }

  // Note that this field has the generic type Comparator<Animal>, *not*
  // Animal.AgeComparator!
  public static final Comparator<Animal> AGE_COMPARATOR = new AgeComparator();

  private final int age;

  Animal(int age) {
    this.age = age;
  }

  public int age() {
    return age;
  }

}

List<Animal> myList = new LinkedList<>();
myList.add(new Animal(10));
myList.add(new Animal(5));
myList.add(new Animal(7));
myList.add(new Animal(9));

Collections.sort(
  myList,
  Animal.AGE_COMPARATOR
);

The public field Animal.AGE_COMPARATOR defines a strategy which can then be used in methods such as Collections.sort, but it does not require the user to know anything about its implementation, not even the implementing class.

If you prefer, you can use an anonymous class:

public class Animal {

  public static final Comparator<Animal> AGE_COMPARATOR = new Comparator<Animal> {
    public int compare(Animal a, Animal b) {
      return a.age() - b.age();
    }
  };

  // other members...
}

If the strategy is a little more complex and requires parameters, it is very common to use static factory methods such as Collections.reverseOrder(Comparator<T>). The return type of the method should not expose any implementation details, e.g. reverseOrder() is implemented like

public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
  // (Irrelevant lines left out.)
  return new ReverseComparator2<>(cmp);
}


Got any Design patterns Question?