Continuing with the samples on patterns that make our development live a little more bearable and building on the shoulders of the not so giant previous post, we are going to face a very common problem: changing the behavior of an existing piece of code. Or putting it in another way, bending it to our purposes.
It's very simple, there are APIs that allow weakly-typed properties. Some of Microsoft's server products include this model in their APIs: you configure the query object to return certain properties and then you access them by name, returning an object. If the property you are requesting was not set up in the query you will get an exception.
All fine, except that sometimes I simply do not want to throw that exception, but a simple null when the property is not defined does the trick. You'll still get the performance hit of the exception, but it'll allow the use of the API in situations where you can't handle exceptions nicely (inside a Linq query, for instance).
If you remember from the previous post, we had our KeyValueAdapter class that could adapt all sorts of indexers. Now we want to modify the behavior of the getters of various of these implementations. One way of achieving this is by sub-classing and I have to admit that it may suit pretty well in this case (is-a relationship) if that was the only behavior to add.
But what we could do if KeyValueAdapter was not written with extensibility in mind or we wanted to add several behaviors?
Looks like a work for the Decorator pattern. But whenever I see some examples of the implementation, they always look clumsy and over complicated to me. Maybe because they demonstrate the whole power of the technique and my concrete example is simple enough to not need as many artifacts.
And that's another beauty of patterns, that you can get the flavor of it and implement your case in an slightly different way. Perhaps your platform has a better (more convenient) way to implement the pattern as opposed to the academic-GoF-way. Or, as my case is, the issue is simple enough to omit some constructions.
But if you maintain the idea and perhaps some of the naming, you code will be crystal-clear to someone familiar with the concept (or at least "googleable" for those with the desire to understand).
Let's see how the code looks like:
As you can see, it's dead-simple but it remains useful and easy to understand. It is way more flexible and extensible than simple inheritance and yet compact and not overly complicated to grasp.
Again, this is real code, from real systems and I did not write it "on purpose", or with the idea of "I have this pattern to demonstrate, let's see if I can grok some example". The problem was there and I thought that applying a flavor of a known way to solve it, might benefit the overall solution.
At least it did not make it worse. Although, to be perfectly honest, I id not think over the alternatives (not that the problem allows showing off)
Time to hit the "envelope".