Looking at the following (simplified) hierarchy of classes:
> Email (base class)
> SimpleEmail extends Email
> HtmlEmail extends Email
I need to decorate Email.send() to add throttling functionality.
I need to instantiate SimpleEmail, HtmlEmail or other similar subclasses of Email.
What should this pattern look like exactly?
My guess (which surly needs correcting) is as follows:
class abstract EmailDecorator
-> Define a constructor: EmailDecorator(Email component)
-> Implements all methods of Email and passes values through to component
-> Adds functionality to send() method
class SimpleEmailDecorator extends EmailDecorator
-> Define a constructor: SimpleEmailDecorator(SimpleEmail component)
-> Implement all methods of SimpleEmail and pass through to component
class HtmlEmailDirector extends EmaiDecorator
-> Same as SimpleEmailDecorator
My brain is not wrapping around how I properly deal with important existing subclasses of the base class that I need to “enhance”. Most examples simplify it down to a point where the inheritance question becomes muddled.
Here’s a simplified example of the decorator pattern. The class hierarchy is restructured as
staticinner classes so that the whole example is contained in one compilation unit (as seen on ideone.com):So here we have a simple
Animalhierarchy, withDogandCatsubclasses. We also have aNormaldecorator — also anAnimal— that simply delegates all methods to anotherAnimal. That is, it doesn’t really do any effective decoration, but it’s ready to be subclassed so that actual decorations can be added.We only have one method here,
makeNoise(). We then have two kinds of actual decorations,LoudandStuttering. (Consider the case whereAnimalhas many methods; thenNormalwould be most valuable).We then have a
keepPokingIt(Animal)method, which takes ANYAnimal, and would do unmentionable things to it until itmakeNoise(). In ourmainfunction, we thenkeepPokingItvarious kinds of animals, decorated with various personality traits. Note that we can even stack one decoration on top of another.The exact implementation details may vary, but this simplified example pretty much captures the essence of the decorator pattern.
Another example:
ForwardingCollectionhierarchy from GuavaIn the above example,
keepPokingItonly cares that it’s anAnimal. Sometimes you may want to just poke aCatand not aDog, or in other ways differentiate the two types. In those kinds of scenarios, you’d then provideNormalCat,NormalDog, etc.If you design your type hierarchy well, this should not be a problem. Remember that you don’t have to write decorators for each implementation
class, but rather one for each type that you care about. Ideally, each type should even be aninterfacerather than a concreteclass.Consider the Java Collections Framework type hierarchy, for example. We have:
interface Collection<E>List<E>,Set<E>,Queue<E>, etcinterface Map<K,V>(which is not aCollection)Guava conveniently facilitates decorator pattern implementations on top of this type hierarchy:
abstract class ForwardingCollection<E>abstractsubclassesForwardingList<E>,ForwardingSet<E>,ForwardingQueue<E>abstract class ForwardingMap<K,V>Note that there is no
ForwardingHashMap<K,V>, or aForwardingTreeSet<E>. There’s probably no need for those anyway.See also
Related questions
ForwardingListusage example