Vertical and Horizontal Decorating
A decorator pattern is one of the best ways to add features to an object without changing its interface. I use composable decorators quite often and always question myself as to how to design them right when the list of features must be configurable. I’m not sure I have the right answer, but here is some food for thought.
Let’s say I have a list of numbers:
interface Numbers { Iterable<Integer> iterate(); }
Now I want to create a list that will only have odd, unique, positive, and sorted numbers. The first approach is vertical (I just made this name up):
Numbers numbers = new Sorted( new Unique( new Odds( new Positive( new ArrayNumbers( new Integer[] { -1, 78, 4, -34, 98, 4, } ) ) ) ) );
The second approach is horizontal (again, a name I made up):
Numbers numbers = new Modified( new ArrayNumbers( new Integer[] { -1, 78, 4, -34, 98, 4, } ), new Diff[] { new Positive(), new Odds(), new Unique(), new Sorted(), } );
See the difference? The first approach decorates ArrayNumbers
“vertically,” adding functionality through the composable decorators Positive
, Odds
, Unique
, and Sorted
.
The second approach introduces the new interface Diff
, which implements the core functionality of iterating numbers through instances of Positive
, Odds
, Unique
, and Sorted
:
interface Diff { Iterable<Integer> apply(Iterable<Integer> origin); }
For the user of numbers
, both approaches are the same. The difference is only in the design. Which one is better and when? It seems that vertical decorating is easier to implement and is more suitable for smaller objects that expose just a few methods.
As for my experience, I always tend to start with vertical decorating since it’s easier to implement but eventually migrate to a horizontal one when the number of decorators starts to grow.
Reference: | Vertical and Horizontal Decorating from our JCG partner Yegor Bugayenko at the About Programming blog. |
You should check out this guy’s idea. It’s my favorite way of composing decorators.
http://blog.codefx.org/design/patterns/decorator-pattern-java-8/
Not that yours is bad; it just kind of hides how to decorate (unless you know about the pattern) and requires an additional 2 apis (Modified and Diff).