Design patterns in C# - The Decorator Pattern
So, after a long break, this week I've decided to revive my series on design patterns in C#, and move on to the decorator pattern!
To use the decorator pattern, you wrap an object in another object in order to extend behaviour. The objects all implement the same interface, so the decorators can stack on top of one another, extendng the behaviour further. Using this pattern, you are able to extend the behaviour of a single object, rather than extending the behaviour of a class as a whole (by e.g. using subclasses).
I think this will be simpler if we run through a (dinosaur related!) example...
Decorator Example
So, say we have a IGigantosaurus
interface, with a single method, Roar
:
And we implement that interface with a class:
What if we then wanted to extend the behaviour of a single Gigantosaurus
so that it could roar more loudly? We could wrap the initial gigantosaurus object in a Decorator
which looks something like this:
But, what if even that wasn't enough and we want the ability to make the Gigantosaurus
roar even more loudly??
We could then have a second Decorator
which extends the behaviour further:
So, if we then build up our wrapped object as follows:
Then the first simple Gigantosaurus
will produce the output: ROAR
.
We then wrap that initial object in both of our decorators to produce the output: ROAR loudly!
. We could then even continue to wrap the object in more of our ExtraLoudGigantosaurus
decorators to make our gigantosaurus ROAR loudly!!!!!!!!!!!!!!
.
In almost all cases, we would expect to call the method on the underlying object, however there are special cases where we might want to, for example, silence our Gigantosaurus
:
And there we have it, a pattern for extending/modifying the behaviour of individual objects. It is worth mentioning that the internal method on the wrapped object can be called before or after the extended behaviour within the implementation (though we probably wouldn't want to add exclamation marks before in our example).
This classic example of this pattern in action, is in the CryptoStream
class in the .NET framework. The CryptoStream
class wraps an ordinary Stream
, but extends the behaviour by encrypting the data before writing to the underlying Stream
, and decrypts before reading from it.
Thanks for reading! Here's a link to the GitHub repository which contains all the code for this blog series. And watch of for my next blog on design patterns in C#!