Sometimes the best way to simplify a method signature is to introduce one or more parameter objects - but how can you do this without just moving the complexity somewhere else?
Here are a some techniques that I’ve used to good effect.
Imagine you are working on some kind of document management system and you’ve written a method to search for documents. Incrementally, as you implemented each user story for searching, you ended up with this signature:
The code works - but this method signature is pretty poor. We have two strings, one for keyword searching of document titles and one for the username of someone who must have been an author. We may specify a range of time during which the document was created and we may specify a range of time during which the document was last updated. Or both. Or neither. We can also request that deleted documents should be returned in the result set and/or that documents we’re not permitted to access should be returned.
Let’s work to improve it.
Perhaps the first code smell to address is the repeated use of pairs of DateTime values to represent a period - or span - of time. Whenever you have a common set of parameters that always appear together, that’s a good indicator of a missing abstraction, a concept that hasn’t been extracted into a class of its own.
Let’s introduce a simple TimePeriod
class (you could make it a struct) that represents such a span.
We could also introduce a helper extension method to make creating TimePeriods more convenient.
Our search method signature has now become this:
[This assumes that TimePeriod is a class - if you decided to make it a struct, you’d need to use TimePeriod?
(a
nullable TimePeriod
) instead, to allow for the case where the period isn’t specified.]
In a real system, we’d likely find widespread use for TimePeriod
- use wouldn’t be limited to this single query
method.
Boolean method parameters are also a strong code smell - in most cases, the presence of a boolean parameter indicates you actually have two different methods that should be implemented separately. Multiple boolean parameters is even worse
- but instead of splitting out into many different methods, one alternative is to introduce an enumeration.
We’ve made our method signature much better, but it’s still not as good as we might hope.
Let’s introduce a parameter object to replace these many parameters with one.
But, haven’t we just moved the complexity to the constructor of the parameter object?
Not necessarily - our parameter object could support a number of configuration methods, allowing it to be set up across multiple lines of code.
One way to do this would be with the classic mutable class:
If you have a preference for immutable objects, the parameter object pattern can still be used. Simply include a
protected
copy constructor and return a new instance from each configuration method.
With this configuration object, our search would look like this.
Comments
blog comments powered by Disqus