The most important thing to remember is that those are guidelines, not rules.
There are cases where a method simply must take an argument. Think about the +
method for numbers, for example. Or the add
method for a collection.
In fact, one might even argue that what it means to add two numbers is dependent on context, e.g. in ℤ 3 + 3 == 6
, but in ℤ|5 3 + 3 == 2
, so really the addition operator should be a method on a context object that takes two arguments instead of a method on numbers that takes one argument.
Likewise, a method for comparing two objects must either be a method of one object taking the other as an argument, or a method of the context, taking two objects as arguments, so it simply doesn't make sense to have a comparison method with less than one argument.
That said, there are a couple of things that can be done to reduce the number of arguments for a method:
- Make the method itself smaller: Maybe, if the method needs that many arguments, it is doing too much?
- A missing abstraction: If the arguments are closely correlated, maybe they belong together, and there is an abstraction you are missing? (Canonical text book example: instead of two coordinates, pass a
Point
object, or instead of passing username and email, pass an IdCard
object.)
- Object state: If the argument is needed by multiple methods, maybe it should be part of the object state. If it is needed by only some of the methods but not others, maybe the object is doing too much and should really be two objects.
One way is to extract the arguments into a new class, but that would surely lead to an explosion of classes?
If your domain model has many different kinds of things, then your code will end up with many different kinds of objects. There's nothing wrong with that.
And those classes are likely to end up with names that violate some of the naming rules (ending with "Data" or "Info" etc)?
If you cannot find a proper name, maybe you either grouped too many arguments together or too few. So, you either have just a fragment of a class or you have more than one class.
Another technique is to make variables used by multiple functions a private member variable to avoid passing them, but that expands the scope of the variable, possibly such that it's open to functions that don't actually need it.
If you have a group of methods all of which operate on the same arguments, and another group of methods that don't, maybe they belong in different classes.
Note how often I used the word "maybe"? That's why those are guidelines, not rules. Maybe your method with 4 parameters is perfectly fine!