Avoid the Telescoping Anti-pattern in Java

The Telescoping anti-pattern is widely-spread, just like a virus. It starts with good intentions. For example, a class that has two properties like this:

public class Example {
	private int x;
	private int y;

	public Example(int x, int y) {
		this.x = x;
		this.y = y;
	}
	...

The above constructor starts being used for creating new Example objects.

Example ex = new Example(2, 4);

At one point, the project requirements change and a third parameter is needed.

For example, let’s assume that the above Example object should support a third dimension and we need a third int property:

public class Example {
	private int x;
	private int y;
	private int z; //new property
...

Consider the fact that the old constructor is already being used with two parameters and you cannot just remove it. Because of that, the easiest solution is to follow the Telescoping anti-pattern:

	public Example(int x, int y, int z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	public Example(int x, int y) {
		this(x, y, 0);
	}

With the above, you preserve the original constructor with two parameters and it calls a new constructor with three parameters and a default value of 0 for z. This will ensure that the new z property will not break previous implementation of the Example object.

This saves you from having to fix older code and that’s why it’s a widely spread practice recognised as a design anti-pattern.

The drawbacks of the telescoping constructor is that it is confusing, ugly and incorrect from clean code point of view. Instead, the correct way to address such a problem with an increasing number of class properties is using the so called Builder.

We can implement the Builder pattern this with with an additional class called ExampleBuilder:

class Example {
	private int x;
	private int y;
	private int z;

	public Example(int x, int y, int z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
}

class ExampleBuilder {
	private int x;
	private int y;
	private int z;

	public ExampleBuilder setX(int x) {
		this.x = x;
		return this;
	}

	public ExampleBuilder setY(int y) {
		this.y = y;
		return this;
	}

	public ExampleBuilder setZ(int z) {
		this.z = z;
		return this;
	}

	public Example build() {
		return new Example(x, y, z);
	}
}

Once you have the builder class, you can instantiate the Example object like this:

	ExampleBuilder eb = new ExampleBuilder();
	eb.setX(1).setY(2).setZ(3);
	Example ex = eb.build();

The above will require fixing your old code in the places where the Example object is instantiated but it will provide you with greater flexibility in future by allowing you to easily add more properties to the Example class.

Comments

So empty here ... leave a comment!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Sidebar



%d bloggers like this: