Behavioral Patterns - Advanced ActionScript 3: Design Patterns, Second Edition (2015)

Advanced ActionScript 3: Design Patterns, Second Edition (2015)

Chapter 7. Behavioral Patterns

Each object used in a adds a specialized behavior. It may be computational or managerial, but regardless of the specifics, the objects aim to facilitate specific goals in a system.

Code that should be encapsulated is too often hard-coded in a class, due to the ease of maintaining scope. Time constraints, lack of practice, and unfamiliarity with better techniques are all reasons a developer may allow non-encapsulated behaviors to add unnecessary lines of code to classes. Doing so can make a class more difficult to maintain and adjust, and decreases the code’s reusability.

Behavioral patterns abstract the objects that are to be messaged. This loosens the couplings between the invoker and the implemented behavior, enabling substitutions between them.

Behavioral patterns offer generalizations that make the relationships of invoker and receiver more flexible. Some behavioral patterns localize an object’s state that a behavior depends on, or is determined by, and others preserve the scope to which the behavior belongs. A few conceal computations and calculations of which an object would be unaware. Strictly speaking, behavioral patterns don’t focus on the encapsulations of behaviors and calculations. They’re concerned with the assignment of those encapsulations to the objects that require them.

This chapter discusses the following patterns: Strategy, Template Method, Command, Chain of Responsibility, Iterator, State, Memento, and Observer.

The Strategy Pattern

The Strategy pattern encapsulates a set of algorithms uniformly (sibling subclasses that inherit a common interface) to achieve interchangeability among them. Figure 7-1 shows the class diagram.

image

Figure 7-1. Strategy pattern class diagram

This pattern has the following parts:

· Abstract strategy

· Concrete strategy

· Abstract context

· Concrete context

· Client

The pattern’s benefits are as follows:

· Algorithms can be used among varying systems

· Algorithms can be more easily maintained

· Algorithms can be interchanged both during development and at runtime

And it has these drawbacks:

· Clients must be aware of the strategies.

· Strategies are more objects to manage.

A Comprehensive Look

The word algorithm may mean something different to a Flash programmer than it does to a computer science major. The term, which sounds mathematical, is defined as “the sum of any and all techniques used to arrive at the desired goal.” In fact, an algorithm may lack any mathematical computations. Essentially, an algorithm represents the actions taken, by any means necessary, to get from point A to point B.

Because there can be numerous ways to arrive at point B, encapsulating behaviors allows the implementations to vary freely. And thus the journey doesn’t always have to be the same.

In order to be polymorphic, each algorithm must possess the same hierarchy; and to remain uniform in their use, the algorithms must expose a shared interface. This way, the data required by the strategy can be passed into that strategy. It’s the responsibility of the abstract algorithm to create both the abstract methods and interfaces that each subclass inherits.

The abstract context, on the other hand, requires knowledge of the abstract algorithm in order to properly arrive at the expected solution and expose the interface to which the client interfaces.

The context and strategy objects must work together to satisfy their needs by providing the appropriate access. There are two ways for this to occur: the context can pass in data to the strategy, or the context can pass itself as the data and allow the strategy to use its interface.

The client in this relationship can identify the behavior of the context. This enables various outcomes without changing the data in the context.

Vignette

Teachers (the client) use various strategies and methods to teach students of varying abilities. They need to differentiate instruction in order to meet the learning needs of all their students. The concepts in the curriculum remain the same, but the way they’re demonstrated and lessons implemented differs based on how a student grasps the information.

For example, when teaching a child how to perform a simple calculation, such as addition, a teacher might begin with the use of manipulatives (strategy A) that help the student understand the concept through a hands-on activity. Children use the physical objects rather than numbers on a page. From there, the teacher puts images of those objects on paper, next to each number in the equation, reinforcing the concept (strategy B). Finally, the teacher substitutes examples containing only numbers for those containing numbers and pictures (strategy C).

The AS3 Cast

In AS3, the Strategy pattern’s parts are as follows:

· Abstract strategy: Exposes the interface a given family of subclassed algorithms inherits and houses any functionality they share. The interface enables the context to retrieve any necessary data or behaviors that make up this set of algorithms.

· Concrete strategy: A specialized algorithm that performs a varied but specialized implementation among a set of algorithms.

· Abstract context: Exposes the interface that can be used by the client. In addition, the abstract context knows which type of behavioral objects can be supplied by the client and retains this reference to defer requests. The abstract context may optionally provide an additional interface that a strategy can use to access pertinent data.

· Concrete context: A specialized context, that through the use of composition, works with a strategy that is submitted by a client, in order to fulfil a behavior.

· Client: Any aspect of the application or system that has prior knowledge of the concrete strategy to be used by the context, as well as the context the client may message.

When It’s Useful

The Strategy pattern is useful when you want to preserve the reuse of algorithms that make up a behavior. Such algorithms are validations, expressions, easing formulas, button logic, and network communications. The Strategy pattern eliminates conditionals among an object state in order to target the appropriate method, via method uniformity.

Example

Often, a web site lets a user contact the company for which the site advertises. Because contact forms vary, it’s valuable to possess the various validation algorithms as individual strategies.

Suppose you have a form field that contains four text fields, which ask users for their first name, last name, e-mail address, and e-mail confirmation. These text fields may require various validations depending on the client or the particular project. For this example, you want to ensure that all required fields are filled in, that the provided e-mail address is valid, that the confirmation e-mail and the original e-mail match, and that no text field contains an expletive.

You begin by devising the abstraction shown in Listing 7-1, which all the validations extend. This makes them uniform and enables polymorphism.

Listing 7-1. AFormValidationBehavior devises the uniformity for a family of algorithms.

package
{
public class AFormValidationBehavior extends Object
{
protected var _formContactForm : IForm;

public function AFormValidationBehavior( form : IForm = null )
{
if (form)
{
_formContactForm = form;
}
}

public function get formContactForm() : IForm
{
return _formContactForm;
}

public function set formContactForm( formContactForm : IForm ) : void
{
_formContactForm = formContactForm;
}

public function validate() : void
{
throw new IllegalOperationError( 'validate must be overridden' );
}
}
}

The form requires a means of abstraction to which it can be referred. In this case, you use IForm and IValidate to reduce the number of excess classes displayed in this code. They contain the getters in the contact form. An example of this can be seen below in Listing 7-2.

Listing 7-2. Abstract form that all validations analyze

package
{
public class ContactForm extends Sprite implements IForm, IValidate
{
protected var _email : FormObject;
protected var _confirmEmail : FormObject;
protected var _firstName : FormObject;
protected var _lastName : FormObject;
protected var _formCollections : Vector.<FormObject>;
protected var _analysis : AFormValidationBehavior;

public function ContactForm()
{
_email = new FormObject();
_confirmEmail = new FormObject();
_firstName = new FormObject();
_lastName = new FormObject();

_formCollections = Vector.<FormObject>( [ _email ,
_confirmEmail ,
_firstName ,
_lastName ] );

_email.packet.data = "iBen@Spilled-Milk.com";
_confirmEmail.packet.data = "iBen@Spilled-Milk.com";
_firstName.packet.data = "Ben";
_lastName.packet.data = "Smith";
}

public function get email() : FormObject
{
return _email;
}

public function set email( email : FormObject ) : void
{
_email = email;
}

public function get firstName() : FormObject
{
return _firstName;
}

public function set firstName( firstName : FormObject ) : void
{
_firstName = firstName;
}

public function get lastName() : FormObject
{
return _lastName;
}

public function set lastName( lastName : FormObject ) : void
{
_lastName = lastName;
}

public function get analysis() : AFormValidationBehavior
{
return _analysis;
}

public function set analysis( analysis : AFormValidationBehavior ) : void
{
_analysis = analysis;
_analysis.formContactForm = this;
trace( _analysis );
}

public function validate() : void
{
_analysis.validate();
}

public function get formCollections() : Vector.<FormObject>
{
return _formCollections;
}

public function get confirmEmail() : FormObject
{
return _confirmEmail;
}

public function set confirmEmail( confirmEmail : FormObject ) : void
{
_confirmEmail = confirmEmail;
}
}
}

Listing 7-3 through Listing 7-7 show the various algorithms in the form-validation family.

Listing 7-3. Algorithm that validates that all required fields are properly filled

package
{
public class RequiredValidation extends AFormValidationBehavior
{
private static const ERROR : String = "All required fields must be filled in";

public function RequiredValidation( form : ContactForm = null )
{
super( form );
}

override public function validate() : void
{
for each ( var fObj:FormObject in _formContactForm.formCollections )
{
var fp : FormPacket = fObj.packet;
if ( fp.isRequired )
{
var cleanser : RegExp = /\s{1,}/gi;
var clone : String = fp.data.replace( cleanser , '' );

if ( clone == '' || clone == fp.prompt )
{
fp.hasErrors = true;
fp.addError( ERROR );
trace( 'error' );
}
}
}
}
}
}

Listing 7-4. Algorithm that validates the provided e-mail address

package
{
public class EmailValidation extends AFormValidationBehavior
{
static protected const EMAIL_EXPRESSION: RegExp =image
/^[a-z][\w.-]+@\w[\w.-]+\.[\w.-]*[a-z][a-z]$/i;

static protected const ERROR : String = "A Valid Email is Required";

public function EmailValidation( form : ContactForm = null )
{
super( form );
}

override public function validate() : void
{
var email : FormObject = this._formContactForm.email;
var emailData : FormPacket = email.packet;
var emailAddy : String = emailData.data;

if (!EMAIL_EXPRESSION.test( emailAddy ))
{
emailData.hasErrors = true;
}
}
}
}

Listing 7-5. Algorithm that validates that both the original e-mail address and the confirmation e-mail match

package
{
public class ConfirmedEmailValidation extends AFormValidationBehavior
{
static protected const ERROR : String = "Emails Must Match";

public function ConfirmedEmailValidation( form : ContactForm = null )
{
super( form );
}

override public function validate() : void
{
var email : FormObject = this._formContactForm.email;
var emailData : FormPacket = email.packet;
var emailAddy : String = emailData.data;

var confirmEmail : FormObject = this._formContactForm.confirmEmail;
var confirmEmailData : FormPacket = confirmEmail.packet;
var confirmEmailAddy : String = confirmEmailData.data;

var match : Boolean = confirmEmailAddy == emailAddy;
if (!match)
{
trace( 'error' );
emailData.hasErrors = true;
emailData.addError( ERROR );
}
}
}
}

Listing 7-6. The profanity-filter abstract algorithm defines the template method, for which subclasses are expected to provide an appropriate filter listing

package
{
public class AProfanityFilter extends AFormValidationBehavior
{
protected static const ERROR : String = 'Please refrain from using obscenities';
protected var profanityAr : Vector.<String>;

public function AProfanityFilter( form : ContactForm = null )
{
super( form );
doProfanity();
}

protected function doProfanity() : void
{
throw new IllegalOperationError( 'doProfanity must be overridden' );
}

override public function validate() : void
{
var field : Vector.<FormObject>= this._formContactForm.formCollections;
for each (var form:FormObject in field)
{
var fp : FormPacket = form.packet;
if (recourse( fp.data ))
{
fp.hasErrors = true;
fp.addError( ERROR );
}
}
}

protected function recourse( str : String , count : uint = 0 ) : Boolean
{
var expressionString : String = (count < profanityAr.length - 1) ? A
'\\b' + profanityAr[count] + '\\b' : profanityAr[count];
var regExp : RegExp = new RegExp( expressionString , 'gix' );
if (regExp.test( str ))
{
return true;
}
else if (count < profanityAr.length - 1)
{
return recourse( str , ++count );
}
return false;
}
}
}

Listing 7-7. Profanity-filter default algorithm that validates by means of RegExp

package
{
public class DefaultProfanityFilter extends AProfanityFilter
{
public function DefaultProfanityFilter( form : ContactForm = null )
{
super( form );
}

override protected function doProfanity() : void
{
profanityAr = Vector.<String>( [ 'Listing of profanities goes here' ] );
}
}
}

Listing 7-8 shows how each algorithm can be substituted for one another to be used with the contact form, in order to validate the appropriate fields. Using the interface IValidate, which exposes only two methods, safeguards the internals.

Listing 7-8. Substitution of algorithms made by the client

var form : IValidate = new ContactForm();

form.analysis = new RequiredValidation();
form.validate();

form.analysis = new EmailValidation();
form.validate();

form.analysis = new ConfirmedEmailValidation();
form.validate();

form.analysis = new DefaultProfanityFilter();
form.validate();

Related Patterns

The following patterns are related to the Strategy pattern:

· State

· Template

The Template Method Pattern

The Template Method pattern defines the skeleton of an algorithm in an operation, deferring steps to subclasses for implementation. Figure 7-2 shows the class diagram.

image

Figure 7-2. Template Method pattern class diagram

This pattern has the following parts:

· Abstract class

· Concrete class

· Client

The pattern’s benefits are as follows:

· Hooks that promote overriding

· Fixed ordering among algorithmic steps

· Specific extension points

A Comprehensive Look

The operations in an abstract class, that define the skeletal composition of the template method, are similar to the bullet points in a topic outline that emphasize a building block of the topic. These bare-boned operations outline the skeleton of an algorithm that a subclass elaborates on. Thus these points form the template, which each subclass needs to model itself to arrive at an end behavior.

Although the subclasses implement specifics, they don’t dictate the order in which the operations are used. This is left up to the abstraction in an effort to localize and maintain the logic among operations.

The Template Method pattern defines the order of the skeletal operations to create uniformity among its subclasses. Primitive operations, which are overridden, are often indicated using the prefix do. (You must prevent subclasses from overriding the template method itself.) The template method increases class cohesion, and provides the necessary hooks into which subclasses can tap.

Vignette

The phrase “Mother knows best” may not always hold true, but a mother does know how she chooses to raise her children. She protects and nurtures them, but she also provides structure. If a mother changes her rules on a daily basis, her children don’t know what path to follow; this is why it’s very important for the mother to solidify this path, and ensure that her children remain on it.

But a mother can’t be there every second of the day. On occasion, the duties of a mother may be passed to a babysitter for a few hours. The babysitter isn’t the mother, doesn’t know what’s best for the children, and has no idea what the parents plan for their children’s future. This is because the babysitter is an individual and doesn’t have the same concerns as the mother. Plus, watching the children is just a way for the babysitter to earn a few extra dollars.

To ensure that the babysitter represents the mother’s presence, the mother must enforce guidelines to be followed while caring for her children. This is accomplished via itemized rules as well as precautionary actions to be taken if anything goes wrong. These actions are detailed and given due diligence on the part of the mother, but what isn’t expressed is the means by which these actions are to be carried out.

The AS3 Cast

In AS3, the Template Method pattern’s parts are as follows:

· Abstract class: Exposes the interface and defines the order of operations necessary to fulfill the obligations of an algorithm. The abstraction must ensure the prevention of its template method.

· Concrete class: Defines the specific implementations of behaviors specified by its abstraction.

· Client: The messenger of the concrete class, which by messaging may trigger the template method. This may be the concrete class itself.

When It’s Useful

The Template Method pattern is useful for doing the following:

· Providing uniformity among subclasses

· Preventing alteration of sequences

· Enforcing factory methods

· Providing additional hooks to which subclasses may specialize

Example

You’ve seen how modularity can promote flexibility. While modules remain in a hierarchy, they can be interchanged, allowing for greater flexibility. Interfaces tie modules together by allowing clients to message their behaviors using a common signature, but an interface doesn’t achieve uniformity of an algorithm to be performed. The Template Method localizes the steps of an algorithm so you can make changes in one place rather than many, thus subclassing the abstraction.

Sections of a web site often use template methods to enforce expected behaviors when a section initiates or exits. Consider these sections of an ActionScript 3 web site: Portfolio, News, About You, Home, and Contact. Each section is written as its own module, and the modules are tied together by their common interface.

Often an abstract class known as ABaseClass defines this interface and extends the flash.display.Sprite object for its interactive properties. ABaseClass’s duties are those of any abstract class: it supplies default behaviors and declares any abstract methods expected to be overwritten by its subclasses. It also creates the inherited interface used by all subclasses that are messaged by the application framework.

Listing 7-9 shows an abstract class that defines an interface that is implemented by all subclasses. ABaseSection also implements a few defaults that are shared among the subclasses. The problem demonstrated in this abstract class is the expectation that subclasses override behaviors, which may already implement a default behavior.

Listing 7-9. ABaseSection acting as an abstract class among modular site sections

package
{
public class ABaseSection extends Sprite
{
protected var _paused : Boolean;
protected var _width : Number;
protected var _height : Number;
protected var _shell : IShell;

public function ABaseSection()
{
}

/*
* Init is the first to be triggered override and load assets
*/
public function init( shell : IShell ) : void
{
_shell = shell;
shell.addEventListener( ShellEvent.EXIT_SECTION , outro );
}

/*
* Pause expects videos, animations, timers, sounds etc... to pause.
*/
public function pause() : void
{
_paused = true;
}

/*
* Unpause expects videos, animations, timers, sounds etc... to resume.
*/
public function unpause() : void
{
_paused = false;
}

public function intro() : void
{
}

/*
* destroy expects memory to be released.
*/
public function destroy() : void
{
_shell.removeEventListener( ShellEvent.EXIT_SECTION , outro );
}

public function updateLayout( width : Number , height : Number ) : void
{
_width = width;
_height = height;
}

protected function outro() : void
{
}
}
}

Any subclass that does as intended and overrides these abstract methods may forget to use the default implementation of the superclass. The problem is that not only do your subclasses require their own logic for their section of the web site, but the superclass in this case, also expects them to recognize when they need to call a superclass method. The dilemma becomes apparent when a subclass extends the abstraction, as shown in Listing 7-10.

Listing 7-10. Home is a specialized type of section and overrides the intro operation to support its own code

package
{
public class Home extends AbstractSection
{
public var introCopyAnimation : MovieClip;
public var background : Bitmap;
public var backgroundContainer : Sprite;

public function Home()
{
backgroundContainer = new Sprite();
background = new HomeBackground();
backgroundContainer.addChild( background );
addChild( backgroundContainer );
}

override public function intro() : void
{
background.intro();
introCopyAnimation = new IntroCopyAnimation();
introCopyAnimation.x = (stage.stageWidth - introCopyAnimation.width) * .5;
introCopyAnimation.y = 175;
addChild( introCopyAnimation );

addEventListener( HomeEvent.ACTIVATE , activate );
addEventListener( HomeEvent.DEACTIVATE , deactivate );
background.addEventListener( HomeEvent.NAVIGATION_ACTIVATE , navigate );
background.addEventListener( HomeEvent.NAVIGATION_DEACTIVATE , navigate );
background.addEventListener( HomeEvent.NAVIGATE_TO_SECTION , navigate );
}

override public function updateLayout( width : Number , height : Number ) : void
{
if (introCopyAnimation)
{
introCopyAnimation.x = (stage.stageWidth - introCopyAnimation.width) * .5;
introCopyAnimation.y = 175;
}

super.updateLayout( width , height );
BestFit.scaleToFill( background , width , height );
background.x = (_width - background.width) * .5;
background.y = (_height - background.height) * .5;
backgroundContainer.scrollRect = new Rectangle( 0 , 0 , width , height );
}

override public function destroy() : void
{
background.destroy();
removeEventListener( HomeEvent.ACTIVATE , activate );
removeEventListener( HomeEvent.DEACTIVATE , deactivate );
background.removeEventListener( HomeEvent.NAVIGATION_ACTIVATE , navigate );
background.removeEventListener( HomeEvent.NAVIGATION_DEACTIVATE , navigate );
background.removeEventListener( HomeEvent.NAVIGATE_TO_SECTION , navigate );
super.destroy();
}
}
}

The reason the Home section will malfunction is because the Home section overrides the parent’s operation and the requests aren’t properly forwarded to the superclass, which fulfills common behavior among all classes. This is only one subclass; but what if the developers creating the other sections make similar mistakes? The sections’ behaviors may be so varied so that the only thing they share is the interface. Therefore, each class is expected to implement its own logic for the interface. The lack of criteria to meet the algorithm defined by the abstract class gets in the way of a uniform structure between the algorithm and the subclasses.

You can handle this by localizing the sequence of steps necessary for an algorithm that lets subclasses implement the code they require, while focusing only on their behaviors and not on what is expected of them by the abstract class. The abstract class must possess the appropriate logic related to the sequences expected of an algorithm, in order to fulfill the appropriate behavior. Adding the skeletal operations lets each subclass define appropriate behaviors without having to consider the when and the why.

Additionally, these abstract operations provide hooks (or callback methods), which can be overridden. This prevents possible effects on the superclass’s default functionality. To preserve the integrity of the entire algorithm in the superclass, you mark it final so no subclass can override it.

The revised ABaseSection in Listing 7-11 uses the Template Method pattern to maintain the appropriate structure of the algorithms the interface suggests. The relationship, which previously required subclasses to defer requests to the superclass, is no longer necessary because the superclass handles this independently of the subclasses. This is referred to as the Hollywood principle (“don’t call you, we’ll call you”): the subclass shouldn’t contact the superclass, because the superclass will be in touch with the subclass.

Listing 7-11. ABaseSection utilizes template methods to devise a consistency among the steps of an operation

package
{
public class ABaseSection extends Sprite
{
protected var _paused : Boolean;
protected var _width : Number;
protected var _height : Number;
protected var _shell : IShell;

public function ABaseSection()
{
}

final public function init( shell : IShell ) : void
{
_shell = shell;
_shell.addEventListener( ShellEvent.EXIT_SECTION , outro );
doLoadAssets();
}

final public function pause() : void
{
_paused = true;
doPauseVideo();
doPauseAnimations();
doPauseTimers();
doPauseSounds();
}

final public function unPause() : void
{
_paused = false
doUnPauseVideo();
doUnPauseAnimations();
doUnPauseTimers();
doUnPauseSounds();
}

final public function intro() : void
{
}

/*
* destroy expects memory to be released.
*/
final public function destroy() : void
{
shell.removeEventListener( ShellEvent.EXIT_SECTION , outro );
doDestroy();
}

final public function updateLayout( width : Number , height : Number ) : void
{
_width = width;
_height = height;
doUpdateLayout();
}

final protected function outro() : void
{
doOutro();
}

protected function doLoadAssets() : void
{
throw new IllegalOperationError( 'doLoadAssets must be overridden' );
}

protected function doPauseVideo() : void
{
throw new IllegalOperationError( 'doPauseVideo must be overridden' );
}

protected function doPauseAnimations() : void
{
throw new IllegalOperationError( 'doPauseAnimations must be overridden' );
}

protected function doPauseTimers() : void
{
throw new IllegalOperationError( 'doPauseTimers must be overridden' );
}

protected function doPauseSounds() : void
{
throw new IllegalOperationError( 'doPauseSounds must be overridden' );
}

protected function doUnPauseVideo() : void
{
throw new IllegalOperationError( 'doUnPauseVideo must be overridden' );
}

protected function doUnPauseAnimations() : void
{
throw new IllegalOperationError( 'doUnPauseAnimations must be overridden' );
}

protected function doUnPauseTimers() : void
{
throw new IllegalOperationError( 'doUnPauseTimers must be overridden' );
}

protected function doUnPauseSounds() : void
{
throw new IllegalOperationError( 'doUnPauseSounds must be overridden' );
}

protected function doDestroy() : void
{
throw new IllegalOperationError( 'doDestroy must be overridden' );
}

protected function doUpdateLayout() : void
{
throw new IllegalOperationError( 'doUpdateLayout must be overridden' );
}

protected function doOutro() : void
{
throw new IllegalOperationError( 'doOutro must be overridden' );
}
}
}

In ActionScript 3, you can use the Template Method pattern to improve the structure of your code and localize uniform behavior. By exposing an interface that can’t be overridden, subclasses are strong armed to override only protected methods.

FAQ

· Does a Template Method ever contain only one step?

Yes, especially in AS3. This helps protect your data. Because you can’t specify virtual or abstract modifiers for methods in AS3, it isn’t clear which methods need to be overridden. This may invite methods marked as protected or public from being overridden. Thus, may encourage overriding operations among interfaces as they use the public modifier.

Instead, by using the Template Method pattern, you can emphasize the method that should be overridden. Because this method is no longer part of the interface, it allows better data hiding because you can mark it protected.

This approach encourages data hiding in the class’s behaviors. The Template Method will help you to make better use of the private and protected modifiers.

· Is a template method supposed to be declared as final?

Yes. No subclass should be able to modify it, because that would interfere with the intended sequence that makes up the algorithm. Also, as in the answer to the first question, if you don’t mark the template method final, you leave the interface open to be overridden.

Related Patterns

The following patterns are related to the Template Method pattern:

· Factory Method

· Strategy

The Command Pattern

The Command pattern encapsulates a request as an object. This abstracts the receiver from being invoked in the application. Figure 7-3 shows the class diagram.

This pattern has the following parts:

image

Figure 7-3. Command pattern class diagram

· Abstract command

· Concrete command

· Invoker

· Receiver

· Client

The pattern’s benefits are as follows:

· Decouples the receiver and the invoker, so the invoker has no bindings among another objects

· Enables undo and redo capabilities

A Comprehensive Look

Anyone who has used an AS3 tweening engine understands the potential of the callback. It lets you trigger or message a method on a tween’s completion. In ActionScript 2.0, the most difficult aspect of the callback was keeping the scope of the object the callback was targeting.

AS3 takes heavy advantage of this pattern in order to achieve method closures, which is why it’s so important to remove event listeners. AS3 doesn’t offer let you tap into these method closures.

The Command pattern captures a request for a given object within its own encapsulation so the request can be passed or stored. Thus objects that are destined to be wrapped inside a command object can be sequenced and queued to be messaged later.

You do this using the Command object, which contains an object, known as a receiver, to message. This way, you conceal the interface of the receiver to be messaged and the intended invoker. The invoker doesn’t need to be aware of anything other than the Command object’s interface. The interface of the Command object is eloquently named execute. This “execute” method, when messaged, defers the request to its receiver and thus targets the appropriate method.

Concrete Commands are written so that they’re aware of the interfaces to the objects that they’re holding. When the command method “execute” is messaged, the appropriate interface of the receiver will be invoked. The interfaces of the receivers intended for messaging vary, so the concrete commands must properly accommodate them. Thus commands and receivers share parallel hierarchies.

The larger the application, the more interfaces are likely to be used and tightly coupled, which can potentially decrease the possibility of code reuse. The Command pattern can conceal such interfaces, so the invoker only knows about the Commander’s particular interface. This provides extremely loose coupling between the sender and the receiver of the message.

The end result is a highly abstracted relay of message requests and invoked behaviors.

Vignette

Johnny’s mother repeatedly informs her son to quit playing video games, make his bed, and clean his room. If Johnny refuses his mother’s requests, it’s just a matter of time before the games are unplugged and he’s grounded. Usually, his mother’s presence and repeated actions invoke his behavior, which is to turn off the game and do his chores.

One Saturday, his mother has to run some errands. Before leaving, she says, “Johnny, I want to see your room cleaned and your bed made when I return in two hours.” Johnny replies, ”Yeah, yeah”, and continues to stare intently at his game.

After a while, a sound from outside causes Johnny to run to the window. Unaware of how much time has passed, he’s worried that his mother is home. Luckily, it’s the next-door neighbor pulling into the driveway. The fear of being grounded causes him to panic and his heart to race, and triggers Johnny’s behavior just as his mother’s presence would. Johnny decides to turn off the console, clean his room, and make his bed.

The AS3 Cast

In AS3, the Command pattern’s parts are as follows:

· Abstract command: Exposes the abstract method execute that all subclasses must implement appropriately. The abstract command also houses the reference of the receiver to which its subclasses are bound.

· Concrete command: The encapsulated request. The concrete command specifies the appropriate method that requires messaging. The concrete command can be either extremely intelligent or absent of any logic necessary to relay the receiver.

· Abstract receiver: Exposes an interface to which a family of commands can relay messages. The receiver’s interface creates sets of commands that can be used in an application.

· Concrete receiver: Holds a specific behavior that it’s requested to perform. As long as a class has an interface, any class can be a receiver.

· Client: The concrete command. The client that uses the Command pattern can be any object that initializes the appropriate command with a receiver. The client instantiates and initializes the receiver.

· Invoker: The object that invokes the execute behavior of a concrete command.

When It’s Useful

The Command pattern is useful for the following:

· Queuing requests to execute later

· Parameterizing a class as a receiver to decouple the request from the action

· Implementing undo/redo commands

Example

A sprite is placed on the stage to act as a button. When a mouse rolls over the button, a specified sound plays. When the mouse moves off the button, the sound stops. The code is shown in Listing 7-12.

Listing 7-12. SoundButton uses a SoundObject to pause and play on hover and rollout

package
{
public class SoundButton extends Sprite
{
private var _snd : Sound;
private var _sndChannel : SoundChannel;

public function SoundButton()
{
addEventListener( MouseEvent.MOUSE_OVER , onHover );
addEventListener( MouseEvent.MOUSE_OUT , onOut );
}

public function get snd() : Sound
{
return _snd;
}

public function set snd( sound : Sound ) : void
{
_snd = sound;
}

private function onHover( me : MouseEvent ) : void
{
_sndChannel = _snd.play();
}

private function onOut( me : MouseEvent ) : void
{
_sndChannel.stop();
}
}
}

This simple example works; but if the button needs to do anything other than exchange your sound reference for another MP3, you have to modify the code. The button was written specifically to operate on sound. Binding the receiver limits code reuse.

If you extract the actions that occur on the mouse events to the container that holds the SoundSprite, you give another class information it shouldn’t know. This isn’t good OOP practice, so you leave the code as it is in the SoundButton.

But now you have a problem: the client makes a last-minute request to have the button play an animation instead of a sound. The SoundButton class no longer does what you need. With your handy editor, you copy and paste the SoundButton code into a new class, which you nameSWFButton (see Listing 7-13).

Listing 7-13. SWFButton uses the MovieClip type

package
{
public class SWFButton extends Sprite
{
private var _swf : MovieClip;

public function SWFButton()
{
addEventListener( MouseEvent.MOUSE_OVER , onHover );
addEventListener( MouseEvent.MOUSE_OUT , onOut );
}

public function get swf() : MovieClip
{
return _swf;
}

public function set swf( mc : MovieClip ) : void
{
_swf = mc;
}

private function onHover( me : MouseEvent ) : void
{
_swf.play();
}

private function onOut( me : MouseEvent ) : void
{
_swf.stop();
}
}
}

Now, when the mouse rolls over the button, you forward the play or stop request to your SWF instance.

The client thinks that although the animation is nice, it doesn’t grab the user’s attention the way the sound did: they want the animation and the sound to play together. You could perform the same copy-and-paste routine, writing more duplicate code. Or you can use the Command pattern to decouple the sender of the request from the receiver, allowing for greater flexibility.

In other words, you conceal the contents you’re messaging—movie clip, sound, both, end so on—in an object that exposes only one execute. This frees your button from being bound to any particular receiver.

To begin, you create an abstract class that represents a given command behavior on a particular receiver interface. It’s the command’s role to create any necessary logic that may be required, to take the responsibility off your button class.

The abstract command object needs to know the interface of the object it’s to make the request of, and to unify any behaviors that can message the intended interface. Your first goal is to refer to Sound and MovieClip as similar objects that they can play and pause, and to allow both types to create their own means of pausing and playing (see Listing 7-14 through Listing 7-17).

Listing 7-14. IPauseable interface

package
{
public interface IPauseable
{
function pause() : void;

function resume() : void;
}
}

Listing 7-15. ExtendedMovieClip can pause and resume

package
{
public class ExtendedMovieClip extends MovieClip implements IPauseable
{
final public function pause() : void
{
this.stop();
}

final public function resume() : void
{
this.play();
}
}
}

Listing 7-16. ExtendedSound can pause and resume

package
{
public class ExtendedSound extends Sound implements IPauseable
{
private var _sndPosition : Number;
private var _sndChannel : SoundChannel;

final public function pause() : void
{
_sndPosition = _sndChannel.position;
_sndChannel.stop();
}

final public function resume() : void
{
_sndChannel = _snd.play( _sndPosition , 0 );
}
}
}

Listing 7-17. ExtendedMovieClipAndSound can pause and resume

package
{
import flash.display.Sprite;

public class ExtendedMovieClipAndSound extends Sprite implements IPauseable
{
private var _mc : ExtendedMovieClip;
private var _snd : ExtendedSound;

final public function pause() : void
{
_mc.pause();
_snd.pause();
}

final public function resume() : void
{
_mc.resume();
_snd.resume();
}
}
}

Now that you’ve created a common interface, you can specify a type of receiver for our abstract Command pattern (see Listing 7-18 through Listing 7-23).

Listing 7-18. ICommand interface

package
{
public interface ICommand
{
function execute() : void;
}
}

Listing 7-19. AbstractPauseableCommand implements ICommand

package
{
public class AbstractPauseableCommand implements ICommand
{
protected var _receiver : IPauseable;

public function AbstractPauseableCommand( aReceiver : IPauseable ) : void
{
_receiver = aReceiver;
}

final public function execute() : void
{
doExecution();
}

final public function set receiver( aReceiver : IPauseable ) : void
{
_receiver = aReceiver;
}

final public function get receiver() : IPauseable
{
return _receiver ;
}

protected function doExecution() : void
{
throw new IllegalOperationError( 'doExecution must be overridden' );
}
}
}

Listing 7-20. PauseCommand extends AbstractPauseableCommand and applies its implementation to the hook as defined in the superclass

package
{
public class PauseCommand extends AbstractPauseableCommand
{
override protected function doExecution() : void
{
_receiver.pause();
}
}
}

Listing 7-21. ResumeCommand extends AbstractPauseableCommand and applies its implementation to the hook as defined in the superclass

package
{
public class ResumeCommand extends AbstractPauseableCommand
{
override protected function doExecution() : void
{
_receiver.resume();
}
}
}

Listing 7-22. ReusableButton uses both commands

package
{
public class ReusableButton extends Sprite
{
private var _exitCommand : ICommand;
private var _hoverCommand : ICommand;

public function ReusableButton()
{
addEventListener( MouseEvent.MOUSE_OVER , onHover );
addEventListener( MouseEvent.MOUSE_OUT , onOut );
}

final public function get hoverCommand() : ICommand
{
return _hoverCommand;
}

final public function set hoverCommand( command : ICommand ) : void
{
_hoverCommand = command;
}

final public function get exitCommand() : ICommand
{
return _exitCommand;
}

final public function set exitCommand( command : ICommand ) : void
{
_exitCommand = command;
}

final private function onHover( me : MouseEvent ) : void
{
_hoverCommand.execute();
}

final private function onOut( me : MouseEvent ) : void
{
_exitCommand.execute();
}
}
}

Listing 7-23. The client uses the commands and the receiver

package
{
public class Client extends Sprite
{
// ...
var whateverPauseable : IPauseable;
// ... rBtn is an instance of your ReusableButton
rBtn.exitCommand = new PauseCommand( whateverPauseable );
rBtn.hoverCommand = new ResumeCommand( whateverPauseable );
}
}

As you can see, you pass in the whateverPauseable instance of IPauseable. This may be an ExtendedSound, an ExtendedMovieClip, or even an ExtendedMovieClipAndSound. The concept that it can be anything is the source of the command’s power. Without having to bind your ReusableButton to a specific object that may change, you can increase the longevity of your button in an ever-changing field.

FAQ

· Can reusable buttons be coupled to IPauseable instances?

In this example yes, because you don’t add excessive logic in the concrete commands that wrap the IPauseable. But imagine if the instance that was being passed in wasn’t intended to pause and resume on rollover, but rather to adjust the tint of a sprite.

Suggesting that this behavior pauses and resumes would confuse any developer. Instead, you’d construct more commands in a similar fashion, continuing to reuse ReusableButton.

· Is a command limited to exposing only the ICommand interface?

No, but creating too many varying interfaces for specific commands will slowly bring ReusableButton back to reusability, similar to that of SoundButton. The more specific the command interfaces, the more bound to a specific type your code becomes.

Rather than use a MOUSE_OVER command and a MOUSE_OUT command, you can enable your command to understand a Boolean value passed in to the execute method. A parameter of True resumes the clip, and False pauses it.

Related Patterns

The following patterns are related to the Command pattern:

· Template Method

· Chain of Responsibility

· Adapter

· Memento

The Chain of Responsibility Pattern

The Chain of Responsibility pattern lets you forward a request to any number of successors required to fulfill the request. Figure 7-4 shows the class diagram.

image

Figure 7-4. Chain of Responsibility pattern class diagram

This pattern has the following parts:

· Abstract handler

· Concrete handler

· Null handler

· Client

The pattern’s benefits are as follows:

· Enables any number of receivers to respond to a request

· Lets you arrange the order dynamically or statically

· Allows a chain to connect parallel receivers in series, unlike events

· Decouples the messenger from the receiver(s) that handle the request

And it has these drawbacks:

· A message may go unhandled, depending on the assembly and the parameter being forwarded.

· Appropriate termination is required.

A Comprehensive Look

The Chain of Responsibility pattern links like-typed objects together to relay a message from the client to each successor in the chain. This decouples the message client from the receiving element meant to handle the request.

The client possesses no knowledge of who the recipient will be once the message is dispatched. Any number of receivers may choose to handle the request, but there is an expected handler. This receiver is said to be an implicit receiver, because it exists and will receive the message (but only the receiver knows this).

Developers who are familiar with the AS3 event system should be aware of this concept. AS3 passes around events without knowing who will receive the request. Handling the request may or may not prevent further forwarding, as also required in the Chain of Responsibility pattern.

Unlike in the AS3 event system, the Chain of Responsibility pattern lets you manipulate the order of the handlers, as well as the handlers responsible in a chain. The client initiates the message to the first handler in the chain. From there, the concrete handlers may or may not choose to handle the request but are expected to forward it further along the chain.

In order to prevent the messaging from continuing, a Null handler must be used, to not only prevent the request from being passed to an undefined successor, but also ensure the chain isn’t infinite. The Null handler caps the end of the chain to signify the end not only to the application but also to the developer.

The client remains unaware whether the request was handled, and if so by which handler. This provides a high degree of flexibility among the various handlers in the chain.

Vignette

Children often play clever games, and one of them is very reminiscent of the Chain of Responsibility pattern. The game has a few names, such as Operator, Grapevine, and Telephone. The goal of the game is to pass a message to the next player (the player’s immediate neighbor), and so on, until the message has been passed from the first receiver of the message to the last available player.

The roles of the players are exactly like those in Chain of Responsibility. The player at the beginning of the line initiates messaging in the chain and injects the necessary data. Each player in the line acts as a receiver and may optionally handle the message but will absolutely forward the request.

As the message travels, each player forwards the message they received to the next player. Because children love to fabricate (some more than others), they may choose to alter the message. Not every player will distort the message: some will forward the message as received, thus abstracting the details of which player in the sequence was responsible for what.

The game concludes when the final receiver is reached and the message is compared to the original. Although this isn’t expected in the Chain of Responsibility pattern, it demonstrates that the messenger is unaware of what the receivers do with the message.

The AS3 Cast

In AS3, the Chain of Responsibility pattern’s parts are as follows:

· Abstract handler: Defines the interface that all handlers possess and supplies default behaviors that are common among its subclasses. The abstract handler may or may not, depending on its implementation, possess a reference of the successor.

· Concrete handler: Has the option to handle the request or continue to propagate it further down the chain.

· Null handler: Provides a fail-safe link. When dealing with the Chain of Responsibility pattern, one of the possible drawbacks is that the sequence must come to an end. If this isn’t properly implemented, an error may occur. Using the Null handler is useful to implement the appropriate end to the request so a concrete handler that happens to be the last in the line doesn’t require unnecessary logic.

· Client: Initiates the message and passes it to the first link in the chain. The client has knowledge of the interface to the abstract handlers.

When It’s Useful

The Chain of Responsibility pattern is useful in the following cases:

· When there may be multiple receivers that can optionally handle the same request

· When you’re creating an event system

· To inject data among a series of objects

Example

Depending on a scenario, you can bubble events and potentially use this approach to decouple objects. But bubbling events can only go so far. Consider the scenario shown in Figure 7-5.

image

Figure 7-5. The display list and its contents

In Figure 7-5, two sprites reside in parallel in the root of an application. One of those sprites contains a nested sprite, childSprite_A. As a member of the flash.display.Sprite hierarchy, childSprite_A can potentially dispatch a MouseEvent when the mouse rolls into the clip’s boundaries. For brevity, this example doesn’t go into the three phases of the event; you only look at the bubbling phase.

As the event is dispatched, much as in the chain of command, it continues to propagate until one of the handlers prevents it from continuing. Because MouseEvents can’t be cancelled, Stage acts as the terminating link; but on the way to Stage, the event passes through Sprite_Aand MainTimeline.

Suppose Sprite_B needs to know if an event is dispatched to childSprite_A. Sprite_B can put the DocumentClass (MainTimeline) in the position of intercepting the propagation. Listing 7-24 shows DocumentClass.

Listing 7-24. DocumentClass

package
{
public class DocumentClass extends MovieClip
{
const SquareSpriteWidth : int = 58;
const SquareSpriteHeight : int = 58;

public function DocumentClass()
{
var sprite_A : Sprite = new CSprite();
sprite_A.name = 'sprite_A';

var sprite-B : Sprite = new CSprite();
sprite_B.name = 'sprite_B';
sprite_B.y = SquareSpriteHeight;

var child_A : Sprite = new CSprite();
child_A.name = 'childSprite_A';
child_A.x = SquareSpriteWidth;

addChild( sprite_B );
addChild( sprite_A );
sprite_A.addChild( child_A );

addEventListener( MouseEvent.MOUSE_OVER , onHover );
}

private function onHover( me : MouseEvent ) : void
{
sprite_B.someMethod();
}
}
}

The code in Listing 7-24 demonstrates how a concrete class can listen for an event, and defer the handling to an object that wasn’t initially part of the propagation chain. Although this approach is effective, the concrete class requires specifics that don’t pertain to it. This decreases the cohesive quality of your class, and spreads code that should be localized.

The Chain of Responsibility pattern lets you achieve this level of localization by appending any number of objects to a chain. To do so, you need a uniform way for Sprite_B to be a part of the chain as a handler. This will rid DocumentClass of any unnecessary handling.

Further tapping into the built-in event system doesn’t achieve the desired behavior, because you have no way to modify the event chain without using Sprite_B as the DisplayObjectContainer of Sprite_A. This means you need to add an additional event listener tochildSprite_A, allowing it to become a client of the message in a new chain (see Listing 7-25 through 7-29).

Listing 7-25. IEventHandler

package
{
public interface IEventHandler
{
function addHandler( IEventHandler ) : void;

function forwardEvent( event : Event ) : void;
}
}

Listing 7-26. AbstractEventHandlerSprite implements IEventHandler

package
{
public class AbstractEventHandlerSprite extends Sprite implements IEventHandler
{
private var _eventHandler : IEventHandler;
static protected const WIDTH : int = 58;
static protected const HEIGHT : int = 58;

public function AbstractEventHandlerSprite()
{
this.graphics.lineStyle( 1 , 0xFFFFFF , 1 );
this.graphics.beginFill( 0x000000 );
this.graphics.drawRect( 0 , 0 , WIDTH , HEIGHT );
}

final public function addHandler( eventHandler : IEventHandler ) : void
{
doAddHandler( eventHandler ) ;
}

final public function forwardEvent( event : Event ) : void
{
doHandleEvent( event );
doForwardEvent( event );
}

protected function doAddHandler( eventHandler : IEventHandler ) : void
{
_eventHandler = eventHandler;
trace( eventHandler + ' added' );
}

protected function doHandleEvent( event : Event ) : void
{
throw new IllegalOperationError( 'doHandleEvent must be overridden' );
}

protected function doForwardEvent( event : Event ) : void
{
_eventHandler.forwardEvent( event );
}

public function get wide() : Number
{
return WIDTH;
}

public function get tall() : Number
{
return HEIGHT;
}
}
}

Listing 7-27. HandlerSprite is a successor of InitiatorSprite

package
{
public class HandlerSprite extends AbstractEventHandlerSprite
{
public function HandlerSprite()
{
super();
}

override protected function doHandleEvent( event : Event ) : void
{
trace( this.name + ' I received the doHandleEvent' );
}
}
}

Listing 7-28. InitiatorSprite initiates the message

package
{
public class InitiatorSprite extends HandlerSprite
{
public function InitiatorSprite()
{
super();
addEventListener( MouseEvent.MOUSE_OVER , onHover , false , 0 , true );
}

private function onHover( me : MouseEvent ) : void
{
this.forwardEvent( me );
}
}
}

Listing 7-29. DocumentClass initiates the Handlers and devises their order of succession

package
{
public class DocumentClass extends Sprite
{
public function DocumentClass()
{
var sprite_A : Sprite = new HandlerSprite();
sprite_A.name = 'sprite_A';

var sprite_B : AbstractEventHandlerSprite = new HandlerSprite();
sprite_B.name = 'sprite_B';
sprite_B.y = sprite_B.tall;

var child_A : AbstractEventHandlerSprite = new InitiatorSprite();
child_A.name = 'childSprite_A';
child_A.x = child_A.wide;

addChild( sprite_B );
addChild( sprite_A );
sprite_A.addChild( DisplayObject( child_A ) );

child_A.addHandler( sprite_B );
// pass sprite_B as the successor of child_A
}
}
}

Currently, when you run this application it appears to work, but it suddenly breaks when you move the mouse over the nested child. This happens because the forwardEvent method is targeted on Sprite_B, which doesn’t have a successor. You could add information in theAbstractEventHandler, but I find it’s easier to follow a chain when a physical object marks the end. This object is the Null handler (see Listing 7-30 and Listing 7-31). This object’s sole purpose is to prevent your loop from failing, and it’s never added to Stage, so it’s appropriate that its type is that of Object.

Listing 7-30. NullHandler reveals the end of the chain. The addition of the NullHandles ensures no conditional statements must be added in order to know when to stop the message from being forwarded

package
{
public class NullHandler extends Object implements IEventHandler
{
public function NullHandler()
{
}

final public function addHandler( handler : IEventHandler ) : void
{
return;
}

final public function forwardEvent( event : Event ) : void
{
trace( 'end of the chain' );
return;
}
}
}

Listing 7-31. DocumentClass from Listing 7-29 now makes use of the NullHandler instance

package
{
public class DocumentClass extends Sprite
{
public function DocumentClass()
{
// ....
child_A.addHandler( sprite_B );
// pass sprite_B as the successor of child_A;
sprite_B.addHandler( new NullHandler );
// pass NullHandler as the successor of sprite_B;

// .. running process traces:
// childSprite_A I received the doHandleEvent
// sprite_B I received the doHandleEvent
// end of the chain
}
}
}

FAQ

· Why do you extend a sprite and implement IEventHandler to form AbstractEventHandlerSprite rather than implement IEventHandler into both HandlerSprite and InitiatorSprite?

The main reason is to establish a class that holds the default code. This reduces the amount of code that must be manually written each time you create a flash.display.Sprite handler. I stress Sprite, because you only use Sprite. The reason to useIEventHandler is given next.

· How can you add a MovieClip as an IEventHandler?

Because this example only uses sprites, you must assume that after doing your due diligence of OOA and OOD, this application is only intended for sprites. Therefore the code is as simple as necessary for this application.

When you introduce another handler type from a hierarchy other than sprites, you have two options, but only one of them uses design patterns and OOP.

First, you can copy and paste the current AbstractEventHandlerSprite code into a new AbstractEventHandlerMovieClip class. You must make sure you add the IEventHandler Implementation so your MovieClip and Sprite can be interchangeable to the IEventHandler interface.

Second, the OOP and design patterns solution uses the Strategy pattern. You must refactor the code and create a new interface for the abstract classes, but some work is necessary.

Related Patterns

The Composite pattern is related to the Chain of Responsibility pattern.

The Iterator Pattern

The Iterator pattern provides sequential access to elements in an aggregate without knowing how the elements are structured. Figure 7-6 shows the class diagram.

image

Figure 7-6. Iterator pattern class diagram

This pattern has the following parts:

· Abstract iterator

· Concrete iterator

· Abstract aggregate

· Concrete aggregate

· Client

The pattern’s benefits are as follows:

· Makes elements of a collection accessible to any number of clients

· Separates maintaining a collection from the objects that require the elements

A Comprehensive Look

You want to store objects in list formation, but as it has been mentioned, classes shouldn’t be exposed to information that doesn’t pertain to them. Therefore, when you think of lists that contain sets of information, you need to consider them in the context of reducing unnecessary information. Think of how you can use them, but decrease what isn’t needed.

AS3 provides various lists through the use of arrays, vectors, objects, and dictionaries. When you try to acquire the elements of an array, the array is often used along with a loop, which should be a localized behavior to the collection. This gives a class that wants to use the elements the freedom to create the logic required to obtain said element. This logic, which retrieves the appropriate element, is the behavior of the object known as an iterator.

The iterator’s responsibility is to maintain the current aggregate and process its successor. There are two types of iterators: internal and external. You can give the internal iterator an algorithm that it applies to every element. The external iterator enables a higher level of control by exposing its interface in such a way that the client can traverse the aggregate. Both have potential benefits and drawbacks. The iterator must ensure that any modification to the aggregate doesn’t negatively impact operations currently traversing the collection.

An example of a collection is the following:

var array : Array = [ 1 , 2 , 3 , 4 , 5 ];

ActionScript 3 provides the internal iterator via for...each...in, every, some, and map loops, as shown in Listing 7-32 and Listing 7-33.

Listing 7-32. Internal iterator encapsulating the traverse logic from the client

var originalArray : Array = [ 1 , 2 , 3 , 4 , 5 ];

for each( var integer : int in originalArray )
{
trace( integer );
}

//... 1
//... 2
//... 3
//... 4
//... 5

Listing 7-33. Internal iterator traversing a collection and applying an algorithm to each element

//...
var array : Array = [ 1 , 2 , 3 , 4 , 5 ];
array.every( tracer );
//... cont

public function tracer( aggregate : int , index : int , collection : Array ) : Boolean
{
trace( aggregate );
return true;
}

//... 1
//... 2
//... 3
//... 4
//... 5

Although ActionScript is kind enough to provide the internal iterator, it fails to offer an external iterator. Internal Iterators conceal the operations required to traverse the elements of the collection, but they don’t let you manually control the traversing. In other words, the iterator traverses all elements in an aggregate without you being able to control the incrementing of the index.

Vignette

An old-fashioned jukebox offers numerous songs that can be played for money. These days, updated jukeboxes are designed to give the nostalgic feeling of an old-time jukebox, making it difficult to distinguish an older model from a newer one. If you’ve never peered inside a jukebox, you may be unaware of how one works. Does it contain records, MP3s, CDs, or HDDs? You don’t know because the workings of the machine aren’t the point—you want the music.

To you, it makes no difference how the jukebox plays, only that it does play. Unfortunately, you did not participate in the collection of songs the jukebox contains. However, you can conveniently move forward and backward through the collection the jukebox supplies. This way, you can work with the presented information as you see fit.

The AS3 Cast

In AS3, the Iterator pattern’s parts are as follows:

· Abstract iterator: Exposes the interface used by the concrete iterator that is necessary for traversing each aggregate

· Concrete iterator: Knows the current position in the aggregate’s traversal and creates the implementations for achieving the intended behavior of the exposed interface

· Abstract aggregate: Defines the interface for maintaining a collection and provides the factory method that manufactures an iterator

· Concrete aggregate: Implements the specific details required of the aggregate interface

· Client: Can be any aspect of the application or system that works with the aggregate to either maintain a collection or obtain the iterator it can traverse

When It’s Useful

The Iterator pattern is useful when you want to do the following:

· Enable a collection to be traversed simultaneously

· Reveal the content of any aggregate in a uniform manner

Example

To create an external iterator, you must provide an interface that a client can use to access the current and next aggregate. The typical iterator interface exposes the ability to see if the end of the collection has been reached, the ability to retrieve the successor of the current element, the ability to reset the position, and the ability to retrieve the current element. You can bundle these four methods into one exposed method, but I prefer to use all four. These methods are shown in Listing 7-34 and form the minimal behavior of the iterator. You can create more specialized versions that can iterate in the reverse direction, or even enable a carousel of elements with no identifiable end.

Listing 7-34. Typical iterator interface

package
{
public interface IIterator
{
function next() : void;

function hasNext() : Boolean;

function reset() : void;

function currentItem() : *;
}
}

The collection itself, requires the appropriate interface to add and remove elements, as well as reveal the length of the the collection. The inteface for the Aggregate is labeled IAggregate as depicted in Listing 7-35

Listing 7-35. Interface of the collection

package
{
public interface IAggregate
{
function count() : int;

function append( item : * ) : Boolean;

function remove( item : * ) : Boolean;
}
}

Lastly, a collection possesses the factory method to return it’s current aggregate as an Iterator to be traversed. Listing 7-36 reveals the IIterate interface which makes use of the current IAgregate interface.

Listing 7-36. Interface of a factory method for the collection

package
{
public interface IIterate extends IAggregate
{
function createIterator( string : String = null ) : IIterator;
}
}

Now that you have the interfaces, you must create the abstractions to which you can add your default behaviors and abstract methods, and finally provide your abstract class with commonalities required by your collections.

Because AS3 provides various ways to use collections—vectors, arrays, and so on—you must ensure that your concrete iterators, and any abstract collection, take this into account. To do so, you construct an abstract collection that an additional layer of abstract classes will subclass. These subclasses are specific to the collections you use (see Listing 7-37 through 7-39).

Listing 7-37. Abstract collection

package
{
public class AbstractCollection implements IIterate
{
protected var _iterator : IIterator;

public function AbstractCollection()
{
}

final public function count() : int
{
return doCount();
}

final public function append( element : * ) : Boolean
{
return doAppend( element );
}

final public function remove( element : * ) : Boolean
{
return doRemove( element );
}

final public function createIterator( string : String = null ) : IIterator
{
return doCreateIterator( string );
}

protected function doCount() : int
{
throw new IllegalOperationError( ' doCount must be overridden' );
return 0;
}

protected function doAppend( element : * ) : Boolean
{
throw new IllegalOperationError( ' doAppend must be overridden' );
return false;
}

protected function doRemove( element : * ) : Boolean
{
throw new IllegalOperationError( ' doRemove must be overridden' );
return false;
}

protected function doCreateIterator( string : String ) : IIterator
{
return null;
}
}
}

Listing 7-38. Abstract Iterator

package
{
public class AbstractIterator extends Object implements IIterator
{
protected var _cursor : int = 0;

final public function next() : void
{
doNext();
}

final public function hasNext() : Boolean
{
return doHasNext();
}

final public function reset() : void
{
doReset();
}

final public function currentElement() : *
{
return doCurrentElement();
}

protected function doNext() : void
{
throw new IllegalOperationError( 'doNext must be overridden ' );
}

protected function doHasNext() : Boolean
{
throw new IllegalOperationError( 'doHasNext must be overridden ' );
return false;
}

protected function doReset() : void
{
throw new IllegalOperationError( 'doReset must be overridden ' );
}

protected function doCurrentElement() : *
{
throw new IllegalOperationError( 'doCurrentElement must be overridden ' );
return null;
}
}
}

Listing 7-39. Abstract array collection that all subclasses that use an array can extend

package
{
public class AbstractArrayCollection extends AbstractCollection
{
protected var _collection : Array;

public function AbstractArrayCollection()
{
super();
_collection = new Array();
}

public function each( func : Function ) : void
{
var tmpIt : IIterator = doCreateIterator( null );
var _count : int = 0;
do
{
func.call( this , tmpIt.currentElement() , _count , _collection );
tmpIt.next();
_count++;
}
while (tmpIt.hasNext());
}

override protected function doCount() : int
{
return _collection.length;
}

override protected function doAppend( element : * ) : Boolean
{
_collection[_collection.length] = element;
return true;
}

override protected function doRemove( element : * ) : Boolean
{
return false;
}

override protected function doCreateIterator( string : String ) : IIterator
{
throw new IllegalOperationError( ' doCreateIterator must be overridden' );
}
}
}

Now that you have the abstract class for arrays defined, you can use your concretes to use the array collections and return a specific iterator that the collection requires by overriding your factory method.

Next you need to extend the abstract iterator to one that is solely focused on arrays as being the collection to iterate. Let’s call this iterator ArrayIterator (see Listings 7-40 through 7-43).

Listing 7-40. ArrayIterator subclasses AbstractIterator to use arrays

package
{
public class ArrayIterator extends AbstractIterator
{
protected var _collection : Array;

public function ArrayIterator( collection : Array )
{
_collection = collection;
}

override protected function doNext() : void
{
_cursor++;
}

override protected function doHasNext() : Boolean
{
return _cursor < _collection.length;
}

override protected function doReset() : void
{
_cursor = 0;
}

override protected function doCurrentElement() : *
{
return _collection[_cursor];
}
}
}

Listing 7-41. Concrete ArrayCollection overriding the factory method to return an array iterator

package
{
public class ArrayCollection extends AbstractArrayCollection
{
public function ArrayCollection()
{
super();
}

override protected function doCreateIterator( string : String ) : IIterator
{
return new ArrayIterator( _collection );
}
}
}

Listing 7-42. The DocumentClass demonstrates the use of internal and external iteration of elements within the ArrayCollection

package
{
public class DocumentClass extends Sprite
{
public function DocumentClass()
{
var arrayCollection : AbstractArrayCollection = new ArrayCollection();
arrayCollection.append( 1 );
arrayCollection.append( 2 );
arrayCollection.append( 3 );
arrayCollection.append( 4 );
arrayCollection.append( 5 );

var it : IIterator = arrayCollection.createIterator();

do
{
trace( it.currentElement() );
it.next();
}
while (it.hasNext());

arrayCollection.each( test );
}

function test( element : int , index : int , arrayCollection : Array ) : Boolean
{
trace( element , index , arrayCollection );
return true;
}
}
}

Listing 7-43. The Iterated results from Listing 7-42

//... The above code traces out the following.
//Utilizing your External Iterator
//... 1
//... 2
//... 3
//... 4
//... 5
//Utilizing your ArrayCollection Internal Iterator and passed function Test
//... 1 0 1,2,3,4,5
//... 2 1 1,2,3,4,5
//... 3 2 1,2,3,4,5
//... 4 3 1,2,3,4,5
//... 5 4 1,2,3,4,5

In AS3, there are built-in collections from which a user can choose, and it may be easier for other developers to use these instead of your new array collection—especially if they’re unfamiliar with the ArrayCollection class. The good thing about separating the iterator from the collection is that having created your ArrayIterator, you can use it along with any built-in AS3 collection by instantiating a new iterator and passing in its appropriate collection (see Listing 7-44).

Listing 7-44. Built-in AS3 array, traversed by instantiating ArrayIterator within the constructor of DocumentClass

public function DocumentClass()
{
var ar : Array = [ 1 , 2 , 3 , 4 , 5 , 6 ];

var itr : IIterator = new ArrayIterator( ar );
do
{
trace( itr.currentElement() + ' via AS3.0 Array ' );
itr.next();
}
while (itr.hasNext());
}

//... traces
//... 1 via AS3.0 Array
//... 2 via AS3.0 Array
//... 3 via AS3.0 Array
//... 4 via AS3.0 Array
//... 5 via AS3.0 Array
//... 6 via AS3.0 Array

FAQ

· Which object is supposed to possess the algorithm, in Listing 7-33, that is to be used with the internal iterator?

The answer lies in the question. The algorithm is a strategy that can be instantiated and used by the internal iterator. This lets you reuse the algorithm with other internal iterators, and allows the strategy to relieve the client and/or the collection from knowing such specifics.

Related Patterns

The Iterator pattern is related to the following patterns:

· Composite

· Factory Method

· Memento

The State Pattern

The State pattern lets you change an object’s behavior to reflect a change in its state. Figure 7-7 shows the class diagram.

image

Figure 7-7. State pattern class diagram

This pattern has the following parts:

· Abstract context

· Abstract state

· Concrete state

· Client

The pattern’s benefits are as follows:

· Localizes operations

· Maximizes cohesion

· Reduces if...else... dependencies

And it has these drawbacks:

· The localization of state specifics causes delocalization among behaviors.

· The pattern requires additional classes.

A Comprehensive Look

A state is a specific variable that can possess a value in a program. This value can be simple and appear insignificant, yet any change to it can determine the operation of a behavior in context.

Consider the effect of destroying a Loader instance in AS3. The means by which you attempt to rid the system of this instance will vary depending on if the Loader has been used or is currently in use. Consider the destroyLoader method shown in Listing 7-45.

Listing 7-45. A typical way to destroy a built-in Loader

protected function destroyLoader() : void
{
loader.contentLoaderInfo.removeEventListener( Event.OPEN , handleOpen );
loader.contentLoaderInfo.removeEventListener( Event.INIT , handleInit );
loader.contentLoaderInfo.removeEventListener( Event.COMPLETE , handleLoadComplete );
loader.contentLoaderInfo.removeEventListener( IOErrorEvent.IO_ERROR ,image
handleLoadIError );
if ( !isLoaded )
{
loader.close();
}
loader.unloadAndStop();
loader = null;
}

As you can see, you destroy the Loader instance with the aid of a conditional statement. You determine if the Loader is currently loading something, and, if so, you’re required to close the Loader before you remove any reference to it. This is a pain.

Unfortunately, the Loader class can’t close and unload itself without the client specifying the condition. This reduces the cohesion of the client and unnecessarily increases the number of lines of code. The issue in the case of the Loader is the lack of change among its behaviors’ functionality; the behaviors are state dependent, as demonstrated in Listing 7-45. This is where the State pattern offers a solution.

The State pattern localizes appropriate behaviors in their own encapsulations that implement the appropriate operations of the given state, thereby reducing the complexities of the messaged object that the client doesn’t need to know about. This pattern uses two components: a state object and the context object.

Because the client remains unaware of the state-dependent behaviors of the object it’s messaging, the messaged object must ensure that the appropriate behaviors reflect the context’s state. The context defines the interface the client uses, and each request is delegated to an encapsulated behavior known as the state object. A finite number of state objects represent all possible states of the context. In the Loader example, the states are Loader.LOADED, Loader.LOADING, and Loader.BARREN.

You have three states, which means you need to create three state objects. All of these states make implementations of the interface, but it’s mandatory that their behaviors reflect their state. In order to make them interchangeable and uniform, they stem from an abstraction, which lets the context use the appropriate implementation at runtime.

What determines the transitions among the states depends entirely on the application. If the application is linear, the context can create the appropriate logic. If it’s more dynamic and varies at runtime, then you have more flexibility to allow each state to enable the appropriate transition. (Here, transition refers to the swapping of state objects; don’t confuse it with animation.)

To enable a state object to trigger the succession of states, it can optionally contain a reference to the context object. If the state object defines the transition’s successor, the state requires the context to expose an additional interface that it can use. This allows state-specific operations to transition to an appropriate state when required. In the Loader example, you have a transition from a loading state to a loaded state when the image loading has completed.

Vignette

Human emotions often vary without rhyme or reason. Although external factors can influence a response, no one can predict the resulting behavior. Each person is different, so even if the stimulus remains constant, the internal changes are often specific to the subject.

A person’s state may not be known, but their behavior and mood reflect their current state of mind. Happy, sad, and angry moods can be recognized by the behaviors you exhibit.

Of course, even if your moods vary, others can still recognize you and will continue to interact with you as they always have. This will just get a different response when they do.

The AS3 Cast

In AS3, the State pattern’s parts are as follows:

· Abstract state: Exposes the interface that the state objects inherit.

· Concrete state: Implements the behaviors of the interface that reflect the state appropriately.

· Abstract context: Exposes the interface that clients message, and in turn delegates requests to the appropriate state object.

· Concrete context: Implements the specifics of the logic that states may transition. It also may contain the factory method that manufactures the appropriate state object.

· Client: Any aspect of the application or system that works with the abstract context. It’s unaware of the state objects because it never works with them directly.

When It’s Useful

The State pattern is useful in these situations:

· To reduce nested conditional statements that reflect a state

· To localize behavior specific to a state

Example

Suppose you’re creating a simple calculator application whose state can be addition, subtraction, multiplication, or division. The calculator’s state is set by the client. (It would be wise to use a model in this case, because the entire application is the calculator; but for brevity, this example uses the client.)

The mode the user chooses adjusts the state of the context. First you need to define the interface of the calculator context. As always, the abstract class contains any default or necessary references used by the subclass. You call this abstract class AbstractCalculatorContext (seeListing 7-46).

Listing 7-46. AbstractCalculatorContext defines the abstract operations

package
{
public class AbstractCalculatorContext
{
protected var _state : AbstractStateObject;

public function AbstractCalculatorContext()
{
}

final public function addition() : void
{
doAddition();
}

final public function subtraction() : void
{
dosubtraction();
}

final public function division() : void
{
doDivision();
}

final public function multiplication() : void
{
doMultiplication();
}

final public function setDilineatedValues( values : Vector.<Number> ) : void
{
doSetDilineatedValues( values );
}

protected function doAddition() : void
{
throw new IllegalOperationError( 'doAddition must be overridden' );
}

protected function dosubtraction() : void
{
throw new IllegalOperationError( 'dosubtraction must be overridden' );
}

protected function doDivision() : void
{
throw new IllegalOperationError( 'doDivision must be overridden' );
}

protected function doMultiplication() : void
{
throw new IllegalOperationError( 'doMultiplication must be overridden' );
}

protected function doSetDilineatedValues( values : Vector.<Number> ) : void
{
throw new IllegalOperationError( 'doSetDilineatedValues must be overridden' );
}
}
}

In order to make the behaviors uniform, you also need to create an abstract state object that defines the interface used by its subclasses. This abstract class is also known by the calculator abstract class, which is called AbstractStateObject. (see Listing 7-47).

Listing 7-47. AbstractStateObject declares a single abstract method as its interface

package
{
public class AbstractStateObject
{
public function calculate( values : Vector.<Number> ) : void
{
throw new IllegalOperationError( 'calculate must be overridden' );
}
}
}

As shown in the listing, the calculate interface accepts any number of values, which are acted on by the appropriate subclass calculations.

Because the user chooses the successor, and not the states themselves, you know it’s a fixed transition, and the successor can be chosen by the context to determine which calculation to use for the state. This is shown in Listing 7-48, where the concrete context instantiates the appropriate state object.

Listing 7-48. Calculator context declares succeeding transitions

package
{
public class CalculatorContext extends AbstractCalculatorContext
{
public function CalculatorContext()
{
}

override protected function doAddition() : void
{
this._state = new AdditionState();
}

override protected function dosubtraction() : void
{
this._state = new SubtractionState();
}

override protected function doDivision() : void
{
this._state = new DivisionState();
}

override protected function doMultiplication() : void
{
this._state = new MultiplicationState();
}

override protected function doSetDilineatedValues( values : Vector.<Number> )image
: void
{
this._state.calculate( values );
}
}
}

CalculatorContext uses a finite number of state objects to adjust the behavior of the calculator. To provide further flexibility, you can encapsulate the creation process using a factory method that returns the appropriate AbstractStateObject (see Listing 7-49).

Listing 7-49. CalculatorContext with the declaration of the factory method

package
{
public class CalculatorContext extends AbstractCalculatorContext
{
protected static const ADDITION_MODE : int = 0;
protected static const SUBTRACTION_MODE : int = 1;
protected static const MULTIPLICATION_MODE : int = 2;
protected static const DIVISION_MODE : int = 3;

public function CalculatorContext()
{
}

override protected function doAddition() : void
{
this._state = doCreateAbstractStateObject( ADDITION_MODE );
}

override protected function doSubtraction() : void
{
this._state = doCreateAbstractStateObject( SUBTRACTION_MODE );
}

override protected function doDivision() : void
{
this._state = doCreateAbstractStateObject( DIVISION_MODE );
}

override protected function doMultiplication() : void
{
this._state = doCreateAbstractStateObject( MULTIPLICATION_MODE );
}

override protected function doSetDilineatedValues( values : Vector.<Number> )image
: void
{
this._state.calculate( values );
}

protected function doCreateAbstractStateObject( EnumType : int )image
: AbstractStateObject
{
throw new IllegalOperationError( 'doFactoryMethod must be overridden' );
return null;
}
}
}

Listing 7-50. Subclass CalculatorContextStateLogic applies the manufacturing logic

package
{
public class CalculatorContextStateLogic extends CalculatorContext
{
override protected function doCreateAbstractStateObject( EnumType : int )image
: AbstractStateObject
{
var product : AbstractStateObject;
switch(EnumType)
{
case ADDITION_MODE:
product = new AdditionState();
break;
case SUBTRACTION_MODE:
product = new SubtractionState();
break;
case MULTIPLICATION_MODE:
product = new MultiplicationState();
break;
case DIVISION_MODE:
product = new DivisionState();
break;
}
return product;
}
}
}

All that remains is to implement the behaviors that reflect the appropriate state among the interfaces the client can use. The implementation for the addition state is shown in Listing 7-51.

Listing 7-51. Addition state implementing its behavior in the calculator interface

package
{
public class AdditionState extends AbstractStateObject
{
public function AdditionState()
{
}

override public function calculate( values : Vector.<Number> ) : void
{
var sum : Number = 0;
for each ( var number:Number in values);
{
sum += number;
}
trace( sum );
}
}
}

Because a change in state can alter the implementation of the behavior, the client doesn’t need to be concerned with how the calculations are performed. This is handled by the state object that the context delegates (see Listing 7-52).

Listing 7-52. The client uses the calculator object without worrying about what state it’s in

package
{
public class Client extends Sprite
{
public function Client()
{
var ti_92Plus : AbstractCalculatorContext = new CalculatorContextStateLogic()

ti_92Plus.addition();
ti_92Plus.setDilineatedValues( Vector.<Number>( [ 2 , 2 ] ) );
ti_92Plus.setDilineatedValues( Vector.<Number>( [ 3 , 9 ] ) );
}
}
}

FAQ

· Isn’t this pattern a lot like the Strategy pattern?

They appear similar at first glance because they both use varying implementations that are encapsulated. They’re also interchangeable because they rely on polymorphic structures. The main distinction between the two is the goal to achieve or the obstacle to overcome.

In the case of the State pattern, the goal is to allow context behaviors to vary and reflect the state of the context. The Strategy pattern lets a client assign the appropriate context behavior without modifying the state. The difference is the dependency between the state and behaviors.

Related Patterns

The State pattern is related to the Strategy pattern.

The Memento Pattern

The Memento pattern externalizes the internal state of an object for later state restoration. Figure 7-8 shows the class diagram.

image

Figure 7-8. Memento pattern class diagram

This pattern has the following parts:

· Memento

· Caretaker

· Originator

· Client

The pattern’s benefits are as follows:

· State reversion

· Increased cohesion

And it has these drawbacks:

· Memory consumption

· Additional classes

· Speed of object initialization, depending on how often mementos are initialized

A Comprehensive Look

Data hiding is a very important principle of OOP; it ensures that no object can change the state of an object without the object’s consent. This allows the object to regulate its own states. For this reason, a class may contain extraneous information that pertains to state maintenance, but that decreases the cohesion among its behaviors. Sometimes an object requires help in concealing such information in order to maintain its states.

This help is in the form of the memento. The memento externalizes the internal state of an object and safeguards its contents from anything other than the originator. Otherwise, anything else would break the principle of data hiding.

The memento can hold any state information the originator allows/requires, but only the originator can supply and obtain the contents of the memento. Depending on the information held in the memento and on the number of mementos in use, mementos can be costly in terms of memory; therefore mementos should remain passive and be created only when necessary.

Mementos aren’t held in the originator because that would be similar to maintaining their mementos, which is a similar burden. Rather than the originators retaining the memento, they pass the mementos to a caretaker.

The caretaker retains mementos for safekeeping. It can only store mementos; it can’t view their contents. If the originator’s state needs to be restored, it obtains the state from the caretaker. The caretaker invokes the factory method, which prompts the creation of a memento from the originator; and it can do so more than once if multiple states are required for the application. You can easily do this by using the Façade pattern (see Chapter 8), or with The Observer Pattern (Discussed at the end of this chapter).

Additionally, a memento may contain incremental changes to create a history of the originator’s changes. If such changes are linear and can be restored in the same order in the stack, then only the retained state should be concerned with those changes, not the originator’s current state. This reduces the amount of memory used.

Mementos can work well with the Command pattern, specifically commands that define both execute and un-execute. In a scenario that uses such a command, the command may become the caretaker.

Vignette

You can use a string tied around your finger as a means of remembering something. The string signifies that you need to remember—it doesn’t fulfill the task of stating what it is you have to remember.

Everyday life requires focus that often drowns out other aspects of the world, resulting in the need to use the string. “But what is this string for?”, you may ask yourself, wishing someone could remind you.

The AS3 Cast

In AS3, the Memento pattern’s parts are as follows:

· Originator: Creates and uses a memento. The originator may be any class in the application that needs to be able to revert its state. The originator implements the IMemento interface or extends from an abstraction if possible, to expose the necessary interface for the caretaker. Additionally, the originator must notify the caretaker when a memento is needed for state reversion.

· Caretaker: Invokes the originator. The caretaker is the messenger of the originator that either obtains or sets a memento for the originator. The caretaker depends on the originator, because it has no way of knowing when the originator has updated its state. Additionally, the caretaker must be informed by the application when restoration to a state is required.

· Memento: A black box. The memento must not reveal its contents to anything other than the originator, because doing so breaches the concept of data hiding. The memento conceals its interface either by using custom namespaces or by declaring its definition as internal.

· Client: The messenger of the originator. Well, not necessarily of the originator, but of the class that implements the IMemento interface, making it an originator. Remember, the originator doesn’t retain its own state, not because it can’t, but because it has other behaviors it needs to perform. These behaviors continue to be messaged by the client, which as always can be any aspect of the application or system. It also notifies the caretaker if a state must be reset or supplied to the originator.

When It’s Useful

The Memento pattern is useful when an object’s state may need to be restored: user input, drawing applications, forms, and so on.

Example

Most applications rely heavily on user interactions to engage and captivate an audience. Unlike our applications (*cough*), humans have flaws and are likely to make mistakes that they want to undo. Rather than expect your objects to maintain a change in their state, the objects set the changes aside for safekeeping, until the object requires them back.

Have you ever had to complete a form online that called for you to enter a lot of text? The text fields in AS3 are great for this type of behavior in an application, but they don’t allow the user to undo data entry, short of using the backspace. The memento can supply this functionality (seeListing 7-53).

Listing 7-53. The IMemento interface defines a narrow interface to obtain and set a memento

package
{
public interface IMemento
{
function setMemento( memento : Memento ) : void;

function makeMomento() : Memento;
}
}

The IMemento interface lets any object possess the interface required to externalize a state (see Listing 7-54 through Listing 7-59).

Listing 7-54. FormField implements IMemento to take advantage of resetting its state

package
{
public class FormField extends TextField implements IMemento
{
use namespace originatorOnly;
public function FormField()
{
}

public function setMemento( memento : Memento ) : void
{
this.text = memento.string;
this.setSelection( memento.cursor , memento.cursor );
}

final public function makeMemento() : Memento
{
var memento : Memento = doMakeMemento();
memento.string = this.text;
memento.cursor = this.caretIndex;
return memento;
}

protected function doMakeMemento() : Memento
{
throw new IllegalOperationError( 'doMakeMomento must be overridden' );
return null;
}
}
}

Listing 7-55. The originatorOnly namespace protects the memento interface from being used beyond the originator

package
{
internal namespace originatorOnly
{
}
}

Listing 7-56. The originator is a subclass of FormField and implements the factory logic

package
{
public class Originator extends FormField
{
use namespace originatorOnly;
public function Originator()
{
super();
}

override protected function doMakeMemento() : Memento
{
return new Memento();
}
}
}

Listing 7-57. The Memento object should be as minimal as possible, because the bytes add up

package
{
public class Memento extends Object
{
private var _string : String;
private var _cursor : int;

public function Memento()
{
trace( getSize( this ) + ' bytes' );
}

originatorOnly function get string() : String
{
return _string;
}

originatorOnly function set string( str : String ) : void
{
_string = str;
}

originatorOnly function get cursor() : int
{
return _cursor;
}

originatorOnly function set cursor( cursor : int ) : void
{
_cursor = cursor;
}
}
}

Listing 7-58. The caretaker creates the logic to determine when a new state snapshot is required

package
{
public class Caretaker extends Sprite
{
public var _stack : Vector.<Memento>;
private var _originator : Originator;
private var _backSpaceMonitor : Array = [];

public function Caretaker( orginator : Originator )
{
_originator = orginator;
_originator.addEventListener( KeyboardEvent.KEY_DOWN , onKeyDown );
_originator.addEventListener( KeyboardEvent.KEY_UP , onKeyUP );
_stack = new Vector.<Memento>();
}

public function onKeyUP( event : KeyboardEvent ) : void
{
if (!event.ctrlKey)
{
if (event.keyCode == Keyboard.BACKSPACE)
{
_backSpaceMonitor[_backSpaceMonitor.length] = true;
}
if (_backSpaceMonitor.length > 1)
{
_backSpaceMonitor.shift();
return;
}
else
{
addStack( _originator.makeMemento() );
}
}
}

public function onKeyDown( event : KeyboardEvent ) : void
{
if (event.ctrlKey && event.keyCode == Keyboard.Z)
{
_originator.setMemento( retrieveStack() );
}
}

private function addStack( memento : Memento ) : void
{
_stack[_stack.length] = memento;
}

private function retrieveStack() : Memento
{
return _stack.pop();
}
}
}

Listing 7-59. DocumentClass initializes the originator and the caretaker

package
{
public class DocumentClass extends Sprite
{
var caretaker : Caretaker;
var ff : FormField;

public function DocumentClass()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

ff = new Originator();
ff.width = 300;
ff.height = 500;
ff.type = TextFieldType.INPUT;
ff.border = true;
addChild( ff );
caretaker = new Caretaker( Originator( ff ) );
}
}
}

In order not to pollute DocumentClass (or any class, for that matter) with listeners, you pass in the originator to the Caretaker instance. This not only increases the cohesiveness of the containing class, but also emphasizes that the caretaker must invoke the originator’s factory method to prevent the application from seeing and possibly modifying the memento.

FAQ

· This example shows how you can retrieve a state when a user presses Ctrl+z, which makes sense here because caretaker already listens for keypresses being dispatched from originator. But how would a reset or undo in a drawing application force the caretaker to submit a saved state?

For the reason mentioned, the caretaker doesn’t expose an interface that will do this. If the ability to reset or step backward is required, the caretaker can optionally implement this functionality to be triggered by the application. This makes the caretaker dependent on the reset or undo button as well.

· Does this example use the Façade pattern or the Observer pattern to retrieve the memento?

This question makes a nice transition, because Observer is the next pattern discussed. The current example uses AS3 event notification for simplification, which isn’t exactly the Observer pattern, as you soon see.

Related Patterns

The Memento pattern is related to these patterns:

· Command

· Iterator

The Observer Pattern

The Observer pattern establishes a one-to-many type of relationship in which objects dependent on information can subscribe to a source for direct notifications. Figure 7-9 shows the class diagram.

image

Figure 7-9. Observer pattern class diagram

This pattern has the following parts:

· Abstract subject

· Concrete subject

· Abstract observer

· Concrete observer

· Client

The pattern’s benefits are as follows:

· Synchronizes state-dependent objects

· Uses a one-to-many relationships

· Lets subjects and observers also be observers and subjects

And it has these drawbacks:

· Object lookup speeds can affect performance.

· It may cause redundant notifications.

A Comprehensive Look

The Observer pattern lets an object that is dependent on the state of another object maintain synchronization when there is a change in state. An object called an observer registers itself with an object possessing a given state, for reasons known only to the observer. The object with which it’s registered is known as the subject because it’s the subject whose state is being observed.

The subject not only exposes an interface, allowing observers access to its states, but also informs all of its observers that a particular value has been updated. This allows the observers to retrieve the updated information to reflect their own states.

The most important aspects of the Observer pattern are the interfaces of the subject and the observer. These vary greatly on the extent to which you wish to implement them, and allow them to be dependent on each other. The simplest subject interface is one that adds and removes an observer. The simplest observer interface is one that can be notified. This requires the abstract classes of both observer and subject to have the default behaviors to perform the duties of these interfaces. This couples the relationship between the two objects.

The alternative is for the subject to declare an interface that allows observers to supply the intended state to watch, and an interface that lets observers to un-watch all or particular aspects. The observer may also let the subject be passed in, allowing state retrieval.

The means by which states are retrieved by observers is called a push and pull. The push and pull are two individual behaviors that obtain data.

· During the push, the subject notifies observers and provides the values each observer requires, pushing its details onto observers.

· During the pull behavior, the subject notifies the observers. It’s up to the observers to retrieve the data, pulling it from the subject.

Both procedures have advantages and disadvantages. Pushing requires the subject to be aware of the interfaces among its observers, but pushing can send information regarding an update of an aspect. Pulling allows the subject to remain unaware of the dependent objects’ interfaces, but requires each observer to be intelligent enough to figure out what may have changed.

Vignette

“If a tree falls in the woods and no one’s around, does it make a sound?” The answer, according to harmonics (physics), is yes; but because no one is there, the sound waves aren’t interpreted, at least not by human ears. You know the tree falling generates a sound, so perhaps the question should be, “If a tree falls in the woods and no one’s around, how do you know the tree fell?”

Perhaps this is a question of existentialism, but it’s also the reason for newspapers. You can’t experience every event firsthand; you need a source for information. Whether your interests are sports, stocks, the daily funnies, or all of these, you can subscribe to updates.

You may subscribe to the paper out of necessity. Business, local, and weather information pertain to information that can impact your life. Being a subscriber to these notifications helps you to behave appropriately.

The benefit of the newspaper is its ability to spread information via a singular channel that can reach the entire town that the local paper covers. The paper, combined with the media you subscribe to on a regular basis, including TV and the Internet, demonstrates your need to remain updated and informed.

The AS3 Cast

In AS3, the Observer pattern’s parts are as follows:

· Subject: Implements ISubject. Subjects aren’t merely subjects, but rather are objects that possess a state that another object needs. The interface inheritance makes a subject a subject. The subject layers additional behaviors that notify dependent objects about state manipulations.

· Observer: Implements IObserver. Observers become observers by adopting and implementing the IObserver interface. They may retain a reference to the subject for added control over the means of obtaining state information from its subject.

· Change manager: Optional object that reduces the couplings among subjects and observers. Push notifications mean the subject must have knowledge of the observer. Pull notifications mean observers must have knowledge of the subject. A change manager acts as a mapping between the two, preventing such couplings.

· Client: Messages subjects and observers. Both subjects and observers are objects with behaviors of their own that don’t pertain to being a subject or an observer. It just so happens that the two are dependent on each another. The client in the system continues to message the two objects as if they were neither subjects nor observers.

When It’s Useful

The Observer pattern is useful when you’re doing the following:

· Devising a model

· Using multiple views to reflect a singular state

Example

AS3 lets you use observers to monitor an aspect of a subject by using the EventDispatcher’s built-in method addEventListener. The word event denotes an action that can manipulate a particular state. The EventDispatcher uses the push method, so details of what has changed often appear in the notification. You can optionally use the pull method by maintaining a reference to the subject that dispatched the notification.

Twitter is the epitome of the Observer pattern, so this example attempts to simulate the act of following a particular Twitter user. A subject changes its status at random intervals using Lorem Ipsum (placeholder text) that is then broadcast to any status-dependent observers. See Listing 7-60 through Listing 7-64.

Listing 7-60. ISubject interface that enables observers to be added to and removed from the subject

package
{
public interface ISubject
{
function addObserver( observer : IObserve , aspect : Function ) : Boolean;

function removeObserver( observer : IObserve ) : Boolean;
}
}

Listing 7-61. IObserve interface defining an operation to be notified

package
{
public interface IObserve
{
function notify( str : String ) : void;
}
}

Listing 7-62. Subject Implements the ISubject interface and updates its status regardless of whether there are observers

package
{
public class Subject extends Object implements ISubject
{
static const LoremIspum : String = "Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Morbi condimentum leo sit amet augue pulvinar non
dictum neque vehicula. Morbi feugiat diam consectetur sapien porta
mattis...";

static const LoremIpsumAr : Array = LoremIspum.split( " " );
protected var _dict : Dictionary;
private var timer : Timer;

public function Subject()
{
_dict = new Dictionary( false );
timer = new Timer( 550 );
timer.repeatCount = 1;
timer.addEventListener( TimerEvent.TIMER_COMPLETE , onComplete );
timer.start();
}

public function removeObserver( observer : IObserve ) : Boolean
{
_dict[observer] = null;
delete _dict[observer];
return true;
}

public function addObserver( observer : IObserve , aspect : Function ) : Boolean
{
_dict[observer] = getTimer();
return true;
}

protected function notifyObservers( Enum : String ) : void
{
for (var observer:* in _dict)
{
observer.notify( Enum );
}
}

private function onComplete( event : TimerEvent ) : void
{
timer.stop();
timer.delay = Math.random() * 1000;
timer.reset();
var startIndex : int = Math.random() * LoremIpsumAr.length;
var pool : int = LoremIpsumAr.length – startIndex;
var endIndex : int = Math.random() * Math.min(pool, 140);
var status : String = "";
while (startIndex < endIndex)
{
status += LoremIpsumAr[startIndex] + " ";
startIndex++;
}

notifyObservers( status );
timer.start();
}
}
}

Listing 7-63. Observer lacks any behaviors for this example other than those of IObserve

package
{
public class Observer extends Object implements IObserve
{
public function Observer()
{
}

// status updates from the Subject will trace out here
public function notify( str : String ) : void
{
trace( str );
}
}
}

Listing 7-64. DocumentClass creates the subject with an instance of an observer

package
{
public class DocumentClass extends Sprite
{
public function DocumentClass()
{
var observer : IObserve = new Observer();
var subject : ISubject = new Subject();

subject.addObserver( observer , null );
}
}
}

This example, although simple, illustrates the essence of the subscriber/notifier method known as the Observer pattern. The subject, an avid Twitter status updater, makes great use of the one-to-many principle by giving any and all subscribers an opportunity to be notified of status updates. When an update occurs, the notification pushes the state to those who depend on it. Of course, the example illustrated a one-to-one relationship, so let’s rectify that to better demonstrate one to many (see Listing 7-65 through Listing 7-67).

Listing 7-65. The TwitterUser class becomes the abstract class of both observer and subject so names can be represented

package
{
public class TwitterUser extends Object
{
private var _twitterName : String

public function TwitterUser( userName : String )
{
_twitterName = username;
}

public function get twitterName() : String
{
return _twitterName;
}

public function set twitterName( twitterName : String ) : void
{
_twitterName = twitterName;
}
}
}

Listing 7-66. Subject and observer both extend TwitterUser

public class Subject extends TwitterUser implements ISubject
public class Object extends TwitterUser implements IObserver

Listing 7-67. Revisiting DocumentClass with many observers monitoring the subject’s status

package
{
public class DocumentClass extends Sprite
{
public function DocumentClass()
{
var subject : ISubject = new Subject( "FeZEC" );

var observer_1 : IObserve = new Observer( "Andrew" );
var observer_2 : IObserve = new Observer( "Mike" );
var observer_3 : IObserve = new Observer( "Ed" );
var observer_4 : IObserve = new Observer( "Lucas" );
var observer_5 : IObserve = new Observer( "Edy" );

subject.addObserver( observer_1 , null );
subject.addObserver( observer_2 , null );
subject.addObserver( observer_3 , null );
subject.addObserver( observer_4 , null );
subject.addObserver( observer_5 , null );
}
}
}

FAQ

· Can observers observe more than one subject?

Absolutely. Because a subject maintains a collection of observers, it’s easier for each observer to do so. The observers just need to tell the subject to add them.

Subjects can also be observers of other subjects. They need to implement the IObserve interface to be able to register themselves with a subject.

· If AS3 has the Observer pattern built in, why is it important to know about the Observer pattern?

All developers should be aware of the foundations on which they build. This gives you greater understanding of how to take advantage of the tools at your disposal. The AS3 Observer model uses the Chain of Responsibility and Composite patterns, which potentially decrease performance. Knowing about the Observer pattern lets you construct alternatives, such as AS3 signals that bypass as much of the built-in event notification as possible.

· Isn’t the Chain of Responsibility pattern the event system in AS3?

The Chain of Responsibility pattern in AS3 is responsible for relaying events. EventDispatcher is responsible for managing and maintaining all subject subscriptions among their observers.

Related Patterns

The Observer pattern is related to these patterns:

· Singleton

Summary

OOD heavily relies on behavioral patterns, because the ultimate goal is to define how objects collaborate with one another. For this reason, these patterns are often implemented in applications and in the AS3 language itself. This isn’t a coincidence: it’s due to the flexibility they offer.

As you may have noticed, behavioral patterns work very well with one another, and with the patterns you learned about previously.

Key Points

· The Strategy pattern offers interchangeability among a family of algorithms.

· The Template Method pattern localizes and protects the steps that make up an expected algorithm.

· The Chain of Responsibility pattern forwards requests in succession to decouple the client from the receiver.

· The Command pattern encapsulates the request to be carried out, decoupling the invoker from the request.

· The Memento pattern externalizes an object’s state.

· Iterators can be external or internal.

· The State pattern may appear to change its class.

· Observers use push and pull methods to notify dependent objects about changes.

· Behavioral patterns are concerned with the assignments of behaviors.