A friend/colleague of mine, George, made an interesting assertion - that he prefers passing implementations, not representations. As we talked and unpacked what he meant by this, I discovered a deceptively simple idea that can make our code significantly more flexible and adaptable.
We can look at the distinction by comparing two examples from the .NET Framework.
When you want to compare two strings, you can (and should!) be explicit about what kind of string comparison you want. In our example here, we’re checking to see whether the current object has a specified name, and we don’t care about letter case.
Here we’ve passed the enumeration value
StringComparison.OrdinalIgnoreCase to represent the kind of comparison we want - internally, the
.Equals() method makes a decision based on that value and delivers the comparison we want.
Now consider what happens when we define a dictionary to map from names to people and we don’t care about letter case:
Carefully note that this time we’re using a
StringComparer, not a
StringComparison. We’re not passing an enumeration value; instead, we’re passing an actual implementation that will do the appropriate comparison for us.
What’s the difference?
String.Equals(), we can only pass one of the predefined values that have already been made available:
Contrast that with the
Dictionary constructor where we could pass any implementation at all:
StringComparer provides easy access to a number of standard implementations that we can easily reuse:
The key point to note here is that we’re not constrained to only use the choices that are pre-baked.
If we wanted our map to ignore whitespace and punctuation, we could create our own comparison class implementing
IEqualityComparer<string> and use that instead.
At the edges of our systems, where we interface with other components or with users, we need to use representations because they serialize to names and other forms that cross those boundaries easily.
But within our systems, passing around the desired implementation instead is a very easy way to make our systems more flexible and more adaptable.
As long as we take the time to ensure that easy things are still easy to achieve - as the .NET Framework does by including the
StringComparer class - we can do this with very low cost.