This is part of a series of recommendations on how to implement some of the famous Gang of Four OOP design patterns using LVOOP. It represents an open discussion with the NI Community, so please feel free to provide comments and suggestions if you have any!
Extend a concrete object’s responsibilities dynamically. Extend the features of an existing class without refactoring tested code.
When refactoring an application to add new features, it’s best to avoid digging into code that has already been tested. This pattern provides a means of extending an object’s functionality without changing the original class’s behavior. The pattern also solves the problem of defining a class whose objects may have any permutation of a set of responsibilities. It creates a scalable and recursive mechanism for defining that set and expanding it in the future.
The attached example uses a coffee store for illustration: you could order your coffee black, or you could want to add double mocha and whipped cream to it. Instead of defining a set of n! subclasses to account for every possible type of drink, you can just define one subclass for each drink and condiment. The subclasses each contain one another and share the same list of methods as one another. When a method is called on an object, that object first calls the same method on its contained object. Then it appends that method’s output with its own data and outputs to the client.
This application can also be viewed as a feature addition to the coffee store after its release. The original coffee store sold simple coffee in four types:
Later, condiments were added. The condiments are also children of Beverage.lvclass, so they take the same data type as the original drink classes (Espresso.lvclass, etc.):
The condiments also have “Cost.vi” and “Get Description.vi” as dynamic dispatch methods, and they contain a single Beverage object as a data element. When a drink like Espresso is instantiated, it can be wrapped up (decorated) by a condiment like Whip. Then the client calls Whip.lvclass:Cost.vi to get the total cost of an espresso with whipped cream. This provides run-time feature extension of the basic drink classes, as well as a scalable means of defining new features with future releases of the software.
[David Staab] This specific example was converted from the Java code provided in Head First Design Patterns, Eric Freeman et. al. 2004. O'Reilly Media, Inc. See the Gang-of-Four text for an example using UI components instead of a world model.
NOTE: "DecoratorPattern_Revised_2013.zip" is a modified version of the first version that cleans up several oddities in the first version. The revised version avoids a whole bunch of replicated strings for the Description and changes how the Description gets generated so that the formatting is not left to each individual class. In the revised version, compare how the Condiment Decorator class computes the Description versus how it generates the Cost. These are two different common techniques for decorating an attribute. The Description is done by having a single method on the Condiment Decorator class that specifies how to reach inside the contained class. The Cost is done by having each class decide how to modify the cost. The second method is appropriate if you were going to have, for example, condiments that multiplied the overall price instead of just adding a value.
David Staab, CLA Staff Systems Engineer National Instruments