Refactoring: Introduce Parameter Object

Smell

Long Parameter List / Data Clump

Let’s say that several methods utilize a repeating set of parameters.

For example, you might have several methods that all receive the same cluster of parameters, possibly in different orders.

public Boolean doStuff(Integer count, String name, List items) {...}
public Integer doThings(Integer count, List items, String name) {...}
public List doItemUpdate(List items, String name, Integer count) {...}

Or you might have a set of parameters that are common to several methods, but, not all methods have the exact same parameters.

public Boolean doStuff(Integer count, Boolean isGood, String name, List items) {...}
public Integer doThings(Integer count, List items, String name) {...}
public List doItemUpdate(List items, String name, Integer count, Collection moreItems) {...}

Why Do I Care?

A cluster of parameters often indicates an object in hiding. In many cases, not only will you end up moving the parameters into a class, but you very well may discover that some of your code will move into the class as well. In this way, parameter clusters can be an indication we have a Single Responsibility Problem.

Solution

Create a new class that will represent your group of parameters.

class MadLibGame {
Integer count = null;
List items = new ArrayList();
String name = null;
…
}

Note - I often do this by starting with an inner class. I defer moving the class to its own file until I have more information. If I end up with a data class with limited use, then it stays an inner class. If I end up moving behavior into the new class, I am more likely to move it to its own file.

Now that we have the parameter object defined, use Add Parameter and add the parameter object to the target method.

public Boolean doStuff(MadLibGame game, Integer count, String name, List items) {
   view.setTitle(name);
   ...
}

Now replace references to the original parameter in the method body with references to the object property. Once all references to the original parameter are removed and all tests pass, remove the original parameter from the method signature.

public Boolean doStuff(MadLibGame game, Integer count, List items) {
   view.setTitle(game.getName());
   ...
}

Continue this process until all object properties are being used and all associated individual parameters are removed.

Look for opportunities to move part of the receiving methods into the parameter object itself by using an extract method and move method. In some cases, it will make sense to move the entire method into the parameter object and you can skip the extract method.

Things to think about

Remember that smells are not rules. Long parameter lists and data clumps are indicators of a potential issue. Take some time to think about what the smell is really telling you.

Let’s say, for example, that you stumble across a class with several parameters in the constructor. The class has several dependencies and the author has opted to use constructor injection. To clean this up, you convert the parameters to method/setter injection. Now, there are no long parameter lists.

Problem Solved?

Only if you think the smell is the problem. It isn’t. A smell is merely an indicator. Hiding the smell doesn’t solve the problem.

In this instance, I’d take a look at the number of dependencies. What is this class supposed to do? Why does it have so many dependencies? What is it doing with each of them? The problem is not the number of parameters to the constructor. If there is a problem, it is more likely that the class has too many responsibilities. The parameters were a clue leading us to dependencies and the dependencies were a clue leading us to responsibility.

As, I often say, “Know The Problem You Are Solving.”