BitDroid

Mixing Chain of Responsibility and Strategy patterns

Philipp Eichhorn • • coding and java

The design pattern Chain of responsibility is a great way of processing data step by step, while separating different functionalities from one another. This works fine in most cases, however stops looking so nice when introducing constructors which take arguments that will not be supplied by the extending classes. Today I have found a solution which takes care of this problem: the strategy pattern.

The good old fashioned way to implement a chain of responsibility is to have one abstract class at the top, that has some abstract method for working with data, and one subclass for each step in the chain.

This could look similar to

public abstract class Processor<D, R> {
	private Processor<R, ?> nextProcessor;

	public final R process(D data) {
		R processedData = processHelper(data);
		if (nextProcessor != null)
			nextProcessor.process(processedData);
		return processedData;
	}

	public final void setNextProcessor(
			Processor<R, ?> nextProcessor) {
		this.nextProcessor = nextProcessor;
	}

	protected abstract R processHelper(D data);
}

… with two sample implementations …

public class Capitalizer extends Processor<String, String> {
	protected String processHelper(String data) {
		return data.toUpperCase();
	}
}

public class Printer extends Processor<String, Void> {
	protected Void processHelper(String data) {
		System.out.println(data);
		return null;
    }
}

… and a small test …

public class Main {
	public static void main(String[] args) {
		Capitalizer capitalizer = new Capitalizer();
		Printer printer = new Printer();
		capitalizer.setNextProcessor(printer);

		capitalizer.process("hello");
		capitalizer.process("world");
	}
}

… which will print HELLO WORLD when executed.

So far this is nothing new and actually a great pattern to use as is. Now let’s assume that we want a little more complicated base processor class with a custom constructor, for example one that takes String name as parameter to be used for logging.

public abstract class Processor<D, R> {
	private final String name;
...
	public Processor(String name) {
		this.name = name;
	}
...
}

Now even though we have just added this one functionality to the base class, we will have to replicate this code over and over in all sub classes, leading to additional work and code replication. This gets worse as constructors get larger and the more extending classes there are.

While coming across this problem at work today, I started thinking about the strategy pattern as a possible solution to this dilemma. This means instead of making the base class abstract and extending it for each processing step, wrapping those steps in strategy instances and passing them to the (not abstract) base class. That way the constructor appears only in one place, all the while preserving overall functionality and code layout.

Here is how that could look for the above example. First add a new interface for representing the strategy class

public interface Strategy<D, R> {
	public R process(D data);
}

… and then refactor the remaining classes to work with this interface …

public class Processor<D, R> {
	private Processor<R, ?> nextProcessor;
	private final Strategy<D, R> strategy;
	private final String name;

	public Processor(
			Strategy<D, R> strategy,
			String name) {

		this.strategy = strategy;
		this.name = name;
	}

	public R process(D data) {
		System.out.println(name + " is processing data");
		R processedData = strategy.process(data);
		if (nextProcessor != null)
			nextProcessor.process(processedData);
		return processedData;
	}

	public void setNextProcessor(
			Processor<R, ?> nextProcessor) {
		this.nextProcessor = nextProcessor;
	}
}

public class Capitalizer implements Strategy<String, String> {
	public String process(String data) {
		return data.toUpperCase();
	}
}

public class Printer implements Strategy<String, Void> {
	public Void process(String data) {
		System.out.println(data);
		return null;
    }
}

public class Main {
	public static void main(String[] args) {
		Printer p = new Printer();
		Capitalizer c = new Capitalizer();

		Processor<String, Void> printer
			= new Processor<String, Void>(p, "Printer");
		Processor<String,String> capitalizer
			= new Processor<String, String>(c, "Capitalizer");
		capitalizer.setNextProcessor(printer);

		capitalizer.process("hello");
		capitalizer.process("world");
	}
}

Unfortunately when using this pattern the client code (Main) gets longer and has to deal with generics, which feels wrong as the types have already been defined by the strategy. The first problem should be acceptable, the second has me still a little troubled. Nevertheless the new pattern helps to reduce code duplication and limits code changes to a minimum number of files.

If you know a solution to the generics part or a different approach all together, feel free to leave comment :)

tl;dr

When implementing a chain of responsibility design pattern with constructors that take arguments which will not be supplied by sub classes, using a strategy pattern for each step in the chain can prevent code duplication.

comments powered by Disqus