When it comes to the number of arguments to pass to a function,
Uncle Bob is pretty clear.
Quoting from Clean Code:
The ideal number of arguments for a function is zero (niladic). Next comes one (monadic),
followed closely by two (dyadic). Three arguments (triadic) should be avoided when possible.
More than three (polyadic) requires very special justification – and then shouldn’t be used anyway.
Still, some objects might have more than 3 attributes or properties and
you usually need some way to initialize them via the constructor.
Some attribute might not be mandatory, therefore on some occasions you can get by with a few overloads
adding more parameters as needed.
Consider the following (contrieved) example from the world of soccer.
I have picked a few attributes that encapsulate the concept of a Team.
Let's try initializing one team:
In this case we are passing 5 arguments into the constructor. Consider that most of the parameters is a string, therefore it's quite easy to get confused and invert the order of some parameter (the first two or the last two). The compiler would not be able to help in this case.
What may help here is a builder object with a fluent interface which can help specifying all the attributes of the team. Something like the following:
Let's see the code for the TeamBuilder class:
The only catch in the solution above is that the caller needs to call Build() at the end of the call chain.
This allows you to create new teams in a more natural way as follows:
The above solution, albeit quite simple, is a good starting point. To make it
ready for real-world code, you should making it more robust with some error checking
(what happens if I omit some call from the chain? If I pass an invalid argument? etc...).
More, you might want to hide the actual implementation from the clients and extract an
interface or abstract class from the concrete TeamBuilder.
This is left to the reader as an excercise :)