Design Patterns using Action Script 3: Structural Patterns (Decorator & Adapter & Composite)
Decorator
Example related in book, that shows use of Decorator Pattern. It´s used when necessary to choose many properties dynamically like the sum of shopping cart products.
File Component.as:
File Decorator.as:
package
{
//Abstract Decorator in Decorator Design Pattern
//**************
//Abstract class
public class Decorator extends Component
{
trace("|*|Decorator|*|");
override public function getInformation():String
{
return information;
}
}
}File ConcreteComponent.as:
package
{
//Concrete Component
public class ConcreteComponent extends Component
{
public function ConcreteComponent():void
{
//\u2794 is Unicode for a right-pointing arrow
information = "Concete Component is decorated with \u2794";
}
}
}File DecConA.as:
package
{
//Concrete Decorator "Alpha"
public class DecConA extends Decorator
{
var components:Component;
public function DecConA(components:Component)
{
this.components=components;
}
override public function getInformation():String
{
return components.getInformation() + " Decoration Alpha:";
}
}
}File DecConB.as:
package
{
//Concrete Decorator "Beta"
public class DecConB extends Decorator
{
var components:Component;
public function DecConB(components:Component):void
{
this.components=components;
}
override public function getInformation():String
{
return components.getInformation() + " Decoration Beta:";
}
}
}File DecTest.as:
package
{
import flash.display.Sprite;
public class DecTest extends Sprite
{
public function DecTest():void
{
//Instantiate Concrete Component
var testComponent:Component = new ConcreteComponent();
//Wrap first decorator around component
testComponent=new DecConA(testComponent);
//Wrap second decorator around component
testComponent=new DecConB(testComponent);
//Output results
trace(testComponent.getInformation());
}
}
}Adapter
Example related in book, that shows use of Adapter Pattern. This pattern allows existing classes to be used in situations that didn´t exist or weren´t anticipated when they were developed.
File Adaptee.as:
package {
public class Adaptee {
public function specificRequest():void {
trace("Called Adaptee:specificRequest()");
}
}
}File Itarget.as:
package {
public interface ITarget {
function request():void
function newOperation():void
}
}File Adapter.as:
package {
public class Adapter implements ITarget {
private var adaptee:Adaptee;
public function Adapter() { // constructor
this.adaptee = new Adaptee();
}
public function request():void {
adaptee.specificRequest();
}
public function newOperation():void {
trace("Called Adapter:newOperation()");
}
}
}File Main.as:
Composite
Example related in book, that shows use of Composite Pattern. The Composite Pattern provides a robust solution to building complex systems that are made up of several smaller components.
File Component.as:
package {
import flash.errors.IllegalOperationError;
// ABSTRACT Class (should be subclassed and not instantiated)
public class Component {
protected var parentNode:Composite = null;
public function add(c:Component):void {
throw new IllegalOperationError("add operation not supported");
}
public function remove(c:Component):void {
throw new IllegalOperationError("remove operation not supported");
}
public function getChild(n:int):Component {
throw new IllegalOperationError("getChild operation not supported");
return null;
}
// ABSTRACT Method (must be overridden in a subclass)
public function operation():void {
}
public function getParent():Composite {
return this.parentNode;
}
internal function setParent(compositeNode:Composite):void {
this.parentNode = compositeNode;
}
internal function removeParentRef():void {
this.parentNode = null;
}
internal function getComposite():Composite {
return null;
}
}
}File Composite.as:
package {
public class Composite extends Component {
protected var sName:String;
protected var aChildren:Array;
public function Composite(sName:String) {
this.sName = sName;
this.aChildren = new Array();
}
override public function add(c:Component):void {
aChildren.push(c);
c.setParent(this);
}
override public function operation():void {
trace(this.sName);
for each (var c:Component in aChildren) {
c.operation();
}
}
override public function getChild(n:int):Component {
if ((n > 0) && (n <= aChildren.length)) {
return aChildren[n-1];
} else {
return null;
}
}
override internal function getComposite():Composite {
return this;
}
private function safeRemove(c:Component) {
if (c.getComposite()) {
c.remove(c); // composite
} else {
c.removeParentRef();
}
}
override public function remove(c:Component):void {
if (c === this) {
// remove all my children
for (var i:int = 0; i < aChildren.length; i++) {
safeRemove(aChildren[i]); // remove children
}
this.aChildren = []; // remove references to children
this.removeParentRef(); // remove my parent reference
} else {
for (var j:int = 0; j < aChildren.length; j++) {
if (aChildren[j] == c) {
safeRemove(aChildren[j]); // remove child
aChildren.splice(j, 1); // remove reference
}
}
}
}
}
}File Leaf.as:
File Main.as:
package {
import flash.display.MovieClip;
/**
* Main Class
* @ purpose: Document class for movie
*/
public class Main extends MovieClip {
public function Main() {
// create root node
var root:Composite = new Composite("root");
// add a node to root
root.add(new Composite("composite 1")); // add node to root as child
root.getChild(1).add(new Leaf("leaf 1")); // add a child leaf
root.getChild(1).add(new Leaf("leaf 2")); // add a child leaf
// add another node
root.add(new Composite("composite 2")); // add node to root as child
root.getChild(2).add(new Leaf("leaf 3")); // add a child leaf
root.getChild(2).add(new Leaf("leaf 4")); // add a child leaf
root.getChild(2).add(new Leaf("leaf 5")); // add a child leaf
// add a child leaf to the root node
root.add(new Leaf("leaf 6"));
trace("display tree");
trace("============");
root.operation();
trace("remove first child of the second child of root");
trace("==============================================");
root.getChild(2).remove(root.getChild(2).getChild(1));
root.operation();
trace("remove the second child of root");
trace("===============================");
root.remove(root.getChild(2));
root.operation();
}
}
}

