Skip to main content

The “Gang of Four” Decorator Pattern: What Is Its Appropriate Use?

Printer-friendly versionSend to friend
“One way to add responsibilities is with inheritance. …” This paragraph describes how a border may be unsuitable for Generalization because it is static and inflexible and a client cannot select which behavior to use or not use. This seems to me to be the type of functionality covered in the third type above.

The remainder of this section is simply a description of layering of Decorators to achieve a desired effect focusing on scroll bars and borders on text areas in which there is an assumption that one may want one, both, or neither on any particular instance. Diagrams show the inheritance structure by which Decorator is implemented.

This situation above in which there are two unrelated sets of characteristics is often referred to as the “Crosstab” problem. I.e., like a table showing one set of options along the top and another set of options along the side, all or most of the cells represent possible combinations of functional requirements. This situation is not limited to only two options, but may involve a large number of different functionality options. Let’s identify Crosstab as a fourth type of functionality to add to the three described above. A crosstab which is not decomposed into separate responsibilities presents a difficulty for Generalization because one must first branch the hierarchy on one option and then branch it on the other. This means that the responsibilities unique to each branch on the second option need to be duplicated in both sides of the tree, violating good design principles. Moreover, the decision of which option to use for the first branch is often arbitrary and thus it is easy for changing requirements to alter the desired order of branching, resulting in a need to rework significant parts of the tree. If the crosstab is expanded to more than two dimensions, it leads to a combinatorially complex tree. Such complexity is exactly what GoF is trying to simplify.

Another observation that we might make about this example is that the functionality discussed is simply present or not present. Moreover, there is no special new functionality associated with the option not being present, it simply doesn’t exist. I.e., adding scroll bars adds new functionality to the base functionality of the text area, but the state of the text area having no scroll bars, the text area has only the base functionality of the text area, not some alternate functionality. This is quite different from a functionality in which there are two or more states, each of which has its own functionality. This is not a different category of functionality since it might apply in each of the four types identified, but it is a significant characteristic of functionality which we might want to notice later on, so let’s call this Unary or One-sided functionality.

Applicability
“Use Decorator:

  • to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects.
  • for responsibilities that can be withdrawn.
  • when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition maybe hidden or otherwise unavailable for subclassing.”

This seems to be a very important section since it is the one that is telling us when to use Decorator.

AttachmentSize
GoFDecorator_20100222.pdf127.66 KB