
At the Institute for Cyber Security, our software architects help fulfill the role of CTOs for new security startups, and will work with development teams to come up with technical solutions to existing development problems. In one recent example, one developer had to modify the behavior of an existing code base but could not modify the code due to licensing.
Normally, the solution is to subclass the original class, then add your behavior as necessary. However, in this case, the class was finalized, meaning the class could not be inherited. This stumped our intrepid developer--surely someone must have solved this problem before!
In software engineering, a design pattern is a general reusable solution to a commonly occurring software design problem. As you may have surmised from the title of this post, our architect recognized the issue and recommended the decorator pattern. This allows new behavior to be added to an existing class dynamically (assuming some design work had been done in advance) as an alternative to subclassing.
The decorator pattern is achieved by designing a new decorator class that wraps the original class. This wrapping could be achieved by the following sequence of steps:
- Create an interface and the base "component" class that implement it.
- Implement the interface into a "decorator" class.
- In the Decorator class, add a Component "pointer" as a field;
- Pass a Component to the Decorator constructor to initialize the Decorator's Component;
- In the Decorator class, redirect all "Component" methods to the internal Component pointer and override any Component method(s) whose behavior needs to be modified.
This pattern is designed so that multiple decorators can be "stacked" on top of each other, each time adding a new functionality to the overridden method(s).
The above listing is best demonstrated by example.Consider the following: we have a Car class which has some functionality we'd like to modify, say by adding a top to the car or an engine. Listing 1 shows a Car interface and SimpleCar class.
To add a top or an engine, we'd need separate classes for each functionality, and an abstract class that they extend (see Listing 2):
Using Listing 3, we can view the results of the Decorator pattern by calling the GetInfo method, which should return "car, with top, with revved engine".
In some dynamic languages, this can be more easily achieved, but in Java, this seals the deal and our developer was able to walk away, not only with a solution to his specific problem, but with a broader understanding of design patterns in general.
Erhan J. Kartaltepe,
erhan.kartaltepe-at-utsa.edu














