Understanding the Decorator Pattern
The basic idea of the Decorator pattern is that new types of objects (decorators) can add new behavior or change existing behavior of a decorated object. The decorators and the decorated object must implement the same interface. That way, the decorator and
The Decorator pattern consists of the following elements:
The following sections look at these elements in more detail. Decorator/Decorated Interface
Everything about the Decorator pattern
package com.peachpit.aas3wdp.decorator {
public interface IWidget {
function getDescription():String;
function run():void;
}
}
Tip
The distinction between decorator and decorated objects might not be immediately clear. Decorators are objects that use composition to add to or modify the behavior of another object at runtime. The object to which the behavior is added or modified is the decorated object. Because decorator objects
Concrete Decorated Class
The concrete decorated class is the basic type that implements the interface. Continuing the example from the
package com.peachpit.aas3wdp.decorator {
public class Widget implements IWidget {
public function Widget() {}
public function getDescription():String {
return "Widget";
}
public function run():void {
trace("running");
}
}
}
This simple decorated type is the basis of the pattern (like the innermost Russian doll). The base decorated type is the foundation on which all other decorators are applied. This example is purposefully simple. It merely implements the two
Abstract Decorator ClassTechnically, all that is required of a decorator is that it implements the same interface as the decorated type. However, practically speaking, most decorators inherit from an abstract decorator class that implements some of the basic functionality such as compositing the decorated object and passing through the method calls. The following example illustrates a basic abstract decorator class for the widget example:
package com.peachpit.aas3wdp.decorator {
public class AbstractWidgetDecorator implements IWidget {
protected var decorated:IWidget;
public function AbstractWidgetDecorator(decoratedWidget:IWidget) {
decorated = decoratedWidget;
}
public function getDescription():String {
return _decorated.getDescription();
}
public function run():void {
_decorated.run();
}
}
}
The Abstract WidgetDecorator class must implement the IWidget interface because it is the same interface implemented by the decorated type ( Widget ). This is the basis of the Decorator patternthat both the decorator and the decorated types implement the same interface. Note that the constructor accepts a parameter of type IWidget . This parameter is the object that the decorator will decorate. Although there's no requirement that you pass the decorated object through the constructor (you could use a different method to accomplish this), it is the convention. It's important that the decorated type is set to the interface rather than a concrete (or abstract) type in order to fully support polymorphism. This approach allows the decorator to decorate not only a concrete decorated type, but also other decorators. It's also important to note that in this example the decorated property is set as protected. By setting the property as protected, it is accessible to subclasses of AbstractWidgetDecorator .
The actual implementation of the methods may vary in every case. In this particular example, each of the methods simply
Concrete Decorator Class(es)The concrete decorator(s) must implement the same interface as the decorated object type. Normally, this is accomplished by extending the abstract decorator class. The decorator class can do the following.
The following code illustrates a concrete decorator for the widget example:
package com.peachpit.aas3wdp.decorator {
public class DigitalWidget extends AbstractWidgetDecorator {
public function DigitalWidget(decorated:IWidget) {
super(decorated);
}
override public function getDescription():String {
var description:String = _decorated.getDescription();
return "digital " + description;
}
}
}
This example declares DigitalWidget to extend AbtractWidgetDecorator . Note that the constructor accepts a parameter of type IWidget , meaning that it could be either a concrete decorated type ( Widget ) or another decorator type. The constructor in this example simply passes along the parameter to the constructor of the superclass.
This example inherits the default implementation for the
run()
method, but it
|