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

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

Chapter 6. Creational Patterns

Creational patterns let you separate the details required to instantiate an object from the architecture. Thus far, a common theme in this book has been how to architect a system that adheres to the four principles of OOP, thereby promoting flexibility. You achieve this flexibility by wrapping code in an object that provides a common interface, shared among other objects. This way, your system can include interchangeable behaviors.

The code is modeled around these interfaces, and the objects’ behaviors are usable once they’re instantiated. However, as simple as this appears on paper, many conditions in reality can render your flexible/reusable code, inflexible/un-reusable.

Listing 6-1 shows how using a concrete instantiation in code limits the method’s flexibility and reuse. Although returnByteArray explicitly references the instantiation of GrayscaleImage, all values returned are always the same—not to mention that you can’t get theByteArray from another existing image. This one reference limits the remaining code’s reusability, without added modification.

Listing 6-1. BitmapDataByteArray returns the ByteArray of GrayscaleImage to a client

public class BitmapDataByteArray
{
public function returnByteArray() : ByteArray
{
var img : BitmapData = new GrayscaleImage( 1 , 1 );
var byteArray : ByteArray = img.getPixels( img.rect );
img.dispose();
img = null;
byteArray.position = 0;
return byteArray;
}
}

That Which Must Not Be Named

The conundrum you’re faced with is how to create an instance of an object that requires particular details, without injecting any algorithms or information unnecessarily into the body of the class. The simplest approach uses parameterization.

When you pass a reference of an object into the welcoming arms of some code, a method, a class, and so on, the code can remain ignorant of the details that created the parameterized object and still use its referenced behaviors.

Unfortunately, parameterization perpetuates the burden of creation. It removes the role of creator from one class and places it into another. In other words, something still has to create the object.

Listing 6-2 shows how the removal of the concrete reference, from the code that uses it, gives the code flexibility for reuse with different instances of the similar BitmapData type. Although returnByteArray doesn’t contain any concrete references, you can see that another body of code is facing the burden of creating the instance.

Listing 6-2. A client instantiates BitmapDataByteArray and passes in a GrayscaleImage

var bitmapDataByteArray:BitmapDataByteArray = new BitmapDataByteArray();
var grayscaleByteArray : ByteArray = bitmapDataByteArray.returnByteArray( new
image GrayscaleImage(1,1));

public class BitmapDataByteArray
{
public function returnByteArray( bmpD : BitmapData ) : ByteArray
{
return bmpD.getPixels(bmpD.rect);
}
}

Creational patterns aren’t intended to replace every occurrence of the new operator, but rather offer a way to conceal concrete implementations from the code that uses the instance. In a nutshell, creational patterns provide solutions to isolate the manufacturing process of concrete instances from the code that uses their interfaces.

The patterns covered in this chapter are as follows: the Factory Method pattern, the Abstract Factory pattern, the Builder pattern, and the Singleton pattern. The discussion of each pattern includes a technical overview, a vignette, an AS3 example, and frequently asked questions.

The technical overview defines the technical specifics of each patterns, its parts, a class diagram, and the pattern’s purpose. The vignette is a real-world example that demonstrates and/or represents each pattern.

All the vignettes in this chapter revolve around the fast-food industry, because it provides many parallels to simplification and abstraction. Then, the example reveals the pattern as it would be used in ActionScript 3 code. Finally, the FAQ section discusses the answers to questions that may arise as you study design patterns.

The Simple Factory

A Simple Factory encapsulates the conditional logic used to create a product. Figure 6-1 shows the class diagram.

image

Figure 6-1. Simple Factory class diagram

A Simple Factory has the following parts:

· Abstract product

· Concrete product

· Concrete creator

· Client

Its benefits are as follows:

· Conceals the logic of product creation

· Only deals with the product interfaces

It also has this drawback:

· Lacks the flexibility to change (change is a constant)

A Comprehensive Look

Simple Factory isn’t a design pattern, but it needs to be included in this chapter because the Factory Method design pattern uses what resembles a simple factory. Often, developers new to design patterns mistakenly think the Factory Method pattern is meant to create objects, giving rise to what has become referred to as the Simple Factory.

The following example doesn’t show how to use the Simple Factory but demonstrates its inflexibility and why you shouldn’t confuse this and the Factory Method pattern.

Example

The creational logic in Listing 6-3 amounts to 46 lines in Shell. Although debugging 46 lines of code isn’t a burden, making changes to 500 lines can be. Each time you make a change to Shell, you risk adding errors. This is never good, especially in an application framework.

Listing 6-3. An excerpt of the 500-lined logic from an application’s framework, labelled Shell

private function createOverlay( overlayType : String , dataObject : * = null ) : void
{
header.disableNavigation();
currentSection.pause();
if (currentOverlay)
{
destroyCurrentOverlay();
}

switch(overlayType)
{
case SectionEvent.VIDEO_OVERLAY:
currentOverlay = new VideoOverlay();
break;
case SectionEvent.PHOTO_OVERLAY:
currentOverlay = new PhotoViewer();
break;
case SectionEvent.AUDIO_OVERLAY:
currentOverlay = new AudioOverlay();
break;
case SectionEvent.TWITTER_OVERLAY:
currentOverlay = new TwitterOverlay();
break;
case OverlayEvent.TWITTER_SUBMIT_OVERLAY:
currentOverlay = new AddTweetOverlay();
break;
}

currentOverlay.y = SiteConfig.HEADER_HEIGHT;
currentOverlay.addEventListener( OverlayEvent.CLOSE_OVERLAY, handleEvent );
currentOverlay.addEventListener( OverlayEvent.INTRO_COMPLETE, handleEvent );
currentOverlay.addEventListener( OverlayEvent.OUTRO_COMPLETE, handleEvent );
currentOverlay.addEventListener( OverlayEvent.PLAY, handleEvent );
currentOverlay.addEventListener( OverlayEvent.SUBMIT_TWEET, handleEvent );

currentOverlay.addEventListener( OverlayEvent.TWITTER_SUBMIT_OVERLAY ,
image handleEvent );

addChild( currentOverlay );

currentOverlay.updateLayout( stage.stageWidth, (stage.stageHeight –
image SiteConfig.FOOTER_HEIGHT - SiteConfig.HEADER_HEIGHT) );

currentOverlay.intro();
}

private function destroyCurrentOverlay() : void
{
}

// ... truncated code

As shown in Listing 6-4, extracting the creational logic in Shell to a new object lets you modify the same lines of code without having to open Shell. This reduces the threat of introducing disaster into a potentially working system.

Listing 6-4.OverlayFactory was created solely to manufacture the appropriate overlay for the system

package
{
public class OverlayFactory
{
public function OverlayFactory()
{
}

public function createOverlay( overlayType : String ) : Overlay
{
var currentOverlay : Overlay;

switch(overlayType)
{
case SectionEvent.VIDEO_OVERLAY:
currentOverlay = new VideoOverlay();
break;
case SectionEvent.PHOTO_OVERLAY:
currentOverlay = new PhotoViewer();
break;
case SectionEvent.AUDIO_OVERLAY:
currentOverlay = new AudioOverlay();
break;
case SectionEvent.TWITTER_OVERLAY:
currentOverlay = new TwitterOverlay();
break;
case OverlayEvent.TWITTER_SUBMIT_OVERLAY:
currentOverlay = new AddTweetOverlay();
break;
}

return currentOverlay;
}
}
}

Extracting the manufacturing of overlays from Shell into the new OverlayFactory object makes change a less disruptive force. You only need to ensure that OverlayFactory is kept as a reference in Shell. This lets Shell continue using instances of overlays but relieves Shell of the burden of creating them.

Listing 6-5. Updated excerpt from Shell demonstrating the reference to OverlayFactory

...
var factory : OverlayFactory = new OverlayFactory();
... cont

header.disableNavigation();
currentSection.pause();

if (currentOverlay)
{
destroyCurrentOverlay();
}

var currentOverlay : Overlay = factory.createOverlay( overlayString );

currentOverlay.y = SiteConfig.HEADER_HEIGHT;
currentOverlay.addEventListener( OverlayEvent.CLOSE_OVERLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.INTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.OUTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.PLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.SUBMIT_TWEET , handleEvent );

currentOverlay.addEventListener( OverlayEvent.TWITTER_SUBMIT_OVERLAY ,
image handleEvent );

addChild( currentOverlay );

currentOverlay.updateLayout( stage.stageWidth , (stage.stageHeight –
image SiteConfig.FOOTER_HEIGHT - SiteConfig.HEADER_HEIGHT) );

currentOverlay. intro();
}

private function destroyCurrentOverlay() : void
{
// ... truncated code

So far, you’ve removed the logic used to create the overlay from the framework that supports the application. You’ve not only reduced the number of lines but also managed to increase the shell’s cohesiveness, by extracting unrelated functions. The point of the framework is to ensure communication among objects, not to develop the necessary logic to create objects. The more cohesive you can make your framework, the fewer reasons you have to keep opening the file to perform frivolous maintenance.

Knowing the importance of the framework, if you need to make any changes to the instantiation logic, you no longer have to concern yourself with Shell. This is beneficial, especially when you’re dealing with multiple developers who are all working toward the same goal. If changes are made to the Shell, developers that may be working on Shell dependant code may also become impeded as well.

Extracting code that manufactures objects adheres to the four principles of OOP, because doing so provides the appropriate boundaries around object creation. This localization of code helps to partition or encapsulate the possibility of variation in your application. In this case, you’re separating the various overlays that may be used in the application.

Although the Simple Factory works at the moment, if you need to add another overlay to the application, you’ll have to edit the Simple Factory. This is the case because you haven’t used an abstract class. To arrive at one of the most important features of OOP—polymorphism—you must use a hierarchy. With a hierarchy, you can make changes while using common code provided by the superclass. Additionally, including a superclass lets you program to an interface, so your factory can exhibit polymorphic capabilities.

The Simple Factory isn’t a design pattern because it doesn’t account for change. Classes should be open to extension but closed to modification.

FAQ

· If you used an abstract class that declares the method createOverlay, subclassed it, and overrode the method, would the Simple Factory then be considered a design pattern?

Yes. It would then be considered a design pattern named Factory Method.

The Factory Method Pattern

The Factory Method pattern encapsulates creational logic in subclasses, allowing them to infer their own implementations. Figure 6-2 shows the class diagram.

image

Figure 6-2. Factory Method pattern class diagram

This pattern has the following parts:

· Abstract product

· Concrete product

· Abstract creator

· Concrete creator

· Client

The pattern’s benefits are as follows:

· Factory methods eliminate the need to bind application-specific classes into your code.

· The code only deals with the product interfaces.

It also has this drawback:

· Sometimes subclasses can’t be created.

A Comprehensive Look

The Factory Method pattern lets you separate the instantiation and the utilization of a product using inheritance. You do so via a method in the creator class, which is the interface a subclass must override and provide an appropriate implementation for. Whereas the superclass is responsible for this abstract method and its signatures, the subclass is privy to the objects that can be instantiated and returned. The subclass uses logic or conditional statements that determine the appropriate object to manufacture.

This approach provides flexibility among possible revisions of the product(s) used, because you can create different implementations by making new subclasses of the abstraction.

The most important aspect of the Factory Method pattern is that product creation is always deferred to a subclass. The reason is the hierarchical relationship that makes polymorphism possible among different implementations.

The method in the factory gives this particular pattern its name; this method’s name reflects the product and the way to achieve the product. The name should make the method easily identifiable as a factory method. Often, the create, get, and make prefixes are used for these method names, to help developers who are familiar with this particular pattern identify its existence in the code.

The superclass is an abstract class that acts as the base class of the manufacturer. As a template for manufacturing, it provides the necessary default behaviors that ensure proper assembly of the object type returned, as well as exposes a factory method that is used by the subclass to define the particular object(s) for creation.

The factory’s subclass has a different role to accompany the superclass. The subclass’s role is to hold the logic necessary in order to choose the object to instantiate for the superclass. This is performed by overriding the exposed factory method and implementing the given logic.

By separating the logic of object creation from the manner in which the object is assembled, you can more easily substitute the logic of the subclass for that of another in the system. By hiding the assembly from the subclass, you also maintain a strict means of assembly without the subclass meddling and trying to assemble the object a particular way. In other words, the abstraction ensures that products are initialized uniformly. It also localizes the particulars between the two classes: the subclass possesses the logic to instantiate a particular product, and the superclass assembles the object because it needs to use that object.

Vignette

MikeDonalds is a franchise restaurant chain. Anyone with the desire to do so can open a franchise as long as they adhere to MikeDonalds’ strict policies; it isn’t Joe Schmo whose name is on the line, but rather MikeDonalds and the company’s continued reputation.

Now Joe Schmo wants to purchase into the MikeDonalds franchise because he feels it will be a huge success in his country where there currently are no MikeDonalds restaurants. The only issue is that Joe Schmo and his fellow countrymen have slightly different tastes than those served by the original MikeDonalds. Bratwurst is a cornerstone of any meal in Joe’s country. Joe convinces MikeDonalds to put a bratwurst sandwich on his restaurant’s menu; but because the MikeDonalds name is at stake, the company takes total ownership of the sandwich’s preparation, cooking, flavor, packaging, and pricing. Joe’s only say in the matter is his suggestion of a product the locals enjoy. To MikeDonalds, the bratwurst as nothing more than a new type of burger to sell.

Meanwhile, another franchise owner has a suggestion for a new product in her Chile location. Because empanadas are common to the area, she suggests empanadas with queso, and MikeDonalds approves the suggestion. To MikeDonalds, it’s just another food item that requires appropriate preparation and packaging.

MikeDonalds views each specific item as a form of a generic product. If it became aware of the empanadas or the bratwurst, the product wouldn’t be reusable when a new, similar product type is offered.

Each franchise owner is a representative (factory subclass) of the MikeDonalds Company as well as the provider of logic regarding which product to create for the customer (client). MikeDonalds is the company (factory) that sets the rules and tone for every product it sells; it can’t afford to have the products prepped any other way, because business might decline. The most freedom the company gives those who purchase into the franchise is the chance to express their understanding about appropriate products to create.

The AS3 Cast

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

· Abstract creator: The manufacturer that defines the type used in its particular factory. A factory can perform nearly any creational operation needed for a class:

· Initialize

· Pull in data

· Configure

· Set states

· Concrete creator: The factory subclass containing the logic necessary to instantiate the appropriate object in a genus of products expected by the superclass.

· Abstract product: The product genus, which exposes the interface that all concrete products of the given genus inherit.

· Concrete product: The physical object that can be instantiated and that extends the abstract product to express itself as a member of the type used in the creator’s logic.

· Client: The abstract creator is, more often than not, the client of the factory method. Although, depending on the scenario, the client may be external to the creator, and may have knowledge among the product’s interface. You’ll see an example of this with the Memento pattern in Chapter 7.

When It’s Useful

The Factory Method pattern is useful in these situations:

· When you don’t know the objects that will be used at runtime, but you’re aware of the common interface

· When you require uniformity/localization among product creation and product assembly

· Any time you use new in a line of code

Example

Revisiting the Shell code from Listing 6-3, you still need to extract the creational logic that returns the appropriate instantiation of an overlay to use.

You know that including an abstraction could have assisted you in the Simple Factory. You can also use the abstraction to separate the logic and the preparation of the product returned. Doing so provides uniformity and flexibility, and saves you from having to add the assembly to each different logic implementation. You want to ensure that the logic can be easily extended, as well as modified.

You extract the Shell logic that created the overlays (see Listing 6-6) and place it for the time being in a class called OverlayFactory, as shown in Listing 6-7. In Listing 6-8, you also remove the preparation of the returned product of the factory to a class calledOverlayPreparation.

Listing 6-6. Revisiting the 500-line excerpt of creational logic in Shell

private function createOverlay( overlayType : String , dataObject : * = null ) : void
{
header.disableNavigation();
currentSection.pause();
if (currentOverlay)
{
destroyCurrentOverlay();
}

switch(overlayType)
{
case SectionEvent.VIDEO_OVERLAY:
currentOverlay = new VideoOverlay();
break;
case SectionEvent.PHOTO_OVERLAY:
currentOverlay = new PhotoViewer();
break;
case SectionEvent.AUDIO_OVERLAY:
currentOverlay = new AudioOverlay();
break;
case SectionEvent.TWITTER_OVERLAY:
currentOverlay = new TwitterOverlay();
break;
case OverlayEvent.TWITTER_SUBMIT_OVERLAY:
currentOverlay = new AddTweetOverlay();
break;
}

currentOverlay.y = SiteConfig.HEADER_HEIGHT;
currentOverlay.addEventListener( OverlayEvent.CLOSE_OVERLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.INTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.OUTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.PLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.SUBMIT_TWEET , handleEvent );
currentOverlay.addEventListener( OverlayEvent.TWITTER_SUBMIT_OVERLAY ,
image handleEvent );

addChild( currentOverlay );

currentOverlay.updateLayout( stage.stageWidth , (stage.stageHeight –
image SiteConfig.FOOTER_HEIGHT - SiteConfig.HEADER_HEIGHT) );

currentOverlay.intro();
}

private function destroyCurrentOverlay() : void
{
// ... implementation not shown
}
// ... truncated code

Listing 6-7. OverlayFactory encapsulates the logic required to instantiate the appropriate overlay

package
{
public class OverlayFactory
{
public function OverlayFactory()
{
}

public function createOverlay( overlayType : String ) : Overlay
{
var currentOverlay : Overlay;

switch(overlayType)
{
case SectionEvent.VIDEO_OVERLAY:
currentOverlay = new VideoOverlay();
break;
case SectionEvent.PHOTO_OVERLAY:
currentOverlay = new PhotoViewer();
break;
case SectionEvent.AUDIO_OVERLAY:
currentOverlay = new AudioOverlay();
break;
case SectionEvent.TWITTER_OVERLAY:
currentOverlay = new TwitterOverlay();
break;
case OverlayEvent.TWITTER_SUBMIT_OVERLAY:
currentOverlay = new AddTweetOverlay();
break;
}

return currentOverlay;
}
}
}

Listing 6-8. OverlayPreparation

package
{
public class OverlayPreparation
{
private var factory : OverlayFactory = new OverlayFactory();
private var currentOverlay : Overlay;

public function OverlayPreparation()
{
}

public function createOverlay( overlayType : String ) : Overlay
{
currentOverlay = factory.createOverlay( overlayType );

currentOverlay.y = SiteConfig.HEADER_HEIGHT;
currentOverlay.addEventListener( OverlayEvent.CLOSE_OVERLAY , handleEvent );

currentOverlay.addEventListener( OverlayEvent.INTRO_COMPLETE , handleEvent );

currentOverlay.addEventListener( OverlayEvent.OUTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.PLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.SUBMIT_TWEET , handleEvent );

currentOverlay.addEventListener( OverlayEvent.TWITTER_SUBMIT_OVERLAY ,
image handleEvent );

currentOverlay.updateLayout( stage.stageWidth , (stage.stageHeight –
image SiteConfig.FOOTER_HEIGHT - SiteConfig.HEADER_HEIGHT) );
return currentOverlay;
}
}
}

The first step in devising a common link is to note the commonalities that these two objects share. The two are, in a way, related in trying to achieve the same goals, and both depend on the product type. This dependency helps to ensure that both the assembler and the factory work toward a final product that doesn’t break the contract between the two classes.

Considering the contract between the two objects, it’s clear that you can use this method to join the two existing classes using inheritance. The common method can be refactored into an abstract class that your subclass can override (see Listing 6-9 and Listing 6-10).

Listing 6-9. AbstractOverlayFactory is the abstract class and declares the createOverlay method

package
{
public class AbstractOverlayFactory
{
public function createOverlay( overlayType : String ) : Overlay
{
throw new IllegalOperationError( 'createOverlay must be overridden' );
return null;
}
}
}

Listing 6-10. OverlayFactory subclasses AbstractOverlayFactory in order to implement logic

package
{
public class OverlayFactory extends AbstractOverlayFactory
{
override public function createOverlay( overlayType : String ) : Overlay
{
var currentOverlay : Overlay;

switch(overlayType)
{
case SectionEvent.VIDEO_OVERLAY:
currentOverlay = new VideoOverlay();
break;
case SectionEvent.PHOTO_OVERLAY:
currentOverlay = new PhotoViewer();
break;
case SectionEvent.AUDIO_OVERLAY:
currentOverlay = new AudioOverlay();
break;
case SectionEvent.TWITTER_OVERLAY:
currentOverlay = new TwitterOverlay();
break;
case OverlayEvent.TWITTER_SUBMIT_OVERLAY:
currentOverlay = new AddTweetOverlay();
break;
}
return currentOverlay;
}
}
}

Currently you generate an abstraction that enables many subclasses to be created by extending AbstractOverlayFactory and overriding createOverlay to implement its logic in determining the appropriate product to return. What you’ve yet to create is the means by which object preparation occurs.

The logic should have zero knowledge of how the object is prepared. Similarly, the preparation shouldn’t know how an overlay is chosen. Both of the two classes should focus on is the product’s type, because this is what maintains compatibility between the classes.

By adding the preparation to the factory abstraction, you get all the benefits without any additional issues. You can also create new subclasses with different logic implementations, and not have to recode their assembly, because only the objects—not their type—change.

Listing 6-11. AbstractOverlayFactory includes the assembly process for the returned object

package
{
public class AbstractOverlayFactory
{
public function makeOverlay( overlayType : String ) : Overlay
{
var currentOverlay : Overlay = createOverlay( overlayType );

currentOverlay.y = SiteConfig.HEADER_HEIGHT;
currentOverlay.addEventListener( OverlayEvent.CLOSE_OVERLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.INTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.OUTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.PLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.SUBMIT_TWEET , handleEvent );
currentOverlay.addEventListener( OverlayEvent.TWITTER_SUBMIT_OVERLAY ,
image handleEvent )

return currentOverlay;
}

protected function createOverlay( overlayType : String ) : Overlay
{
throw new IllegalOperationError( 'createOverlay must be overridden' )
return null
}
}
}

To ensure that preparation is used and not bypassed, AbstractOverlayFactory removes createOverlay as part of its interface so that only the superclass can call it. As a protected method, each subclass overrides createOverlay with its chosen implementation; and preparation is ensured because that process is in the additional method makeOverlay. The makeOverlay method has become the factory method that any client may message; in return, the client gets a product. Although this example returns the assembled product to an external client, this isn’t always the case. Even the abstraction can be the client of the product, as well as the invoker of the factory method.

makeOverlay delegates the responsibility of creating an overlay to the logic in an encapsulated creator. Because the subclass and the abstract class both rely on the product type, the union between product preparation and creation is localized into one object, while maintaining great cohesion for maintenance.

What results from the factory method is a cohesive set of classes that localize common behavior in a product to be used in a system. By using inheritance, you can partition preparation from instantiation while abstracting the product from the client.

Localization and the union between preparation and creation are so well contained that it appears as if all you’re instantiating is a class that implements the logic for object instantiation.

FAQ

· If the subclass and the superclass form the factory, and both know about the abstract product, why separate the logic from the assembly?

You should keep the code localized for ease of maintenance. However, by injecting the means to package and prepare a product into the logic, you remove the flexibility to add or remove new products without physical maintenance of the object. The separation offers flexibility through its use of inheritance.

· If each product differs in the way it needs to be assembled or prepared, should a subclass have more control than the abstract over the means of preparing each object?

The factory method focuses on one abstract type to return. If the assembly of a particular object varies from other objects of its type, it may be unabstracted. If this isn’t the case, you can use the Builder pattern with the factory method. However, a subclass shouldn’t have any knowledge about the preparation.

· If the subclass is a smarter and more specialized form of the superclass, shouldn’t you be able to modify the methods declared in the abstract if they need to be more specific?

As stated in the previous answer, a subclass shouldn’t have any knowledge about the preparation of the product. If each concrete class could modify the logic and the preparation, the hierarchy could have infinite levels. This would be poor practice, because if any change occurred in the lower levels of a subclass, an error could present itself in any subclass.

· Can a factory build more than one product?

Yes, a factory can return more than one product. Ensure that each factory method is named appropriately for the product being returned. If the products need to reside together as a set, consider the next pattern: Abstract Factory.

Related Patterns

The following patterns are related to the Factory Method pattern:

· Abstract Factory

· Builder

· State

· Template Method

The Abstract Factory Pattern

The Abstract Factory pattern provides an interface for creating families of related products while concealing the object-instantiation process. Figure 6-3 shows the class diagram.

image

Figure 6-3. Abstract Factory pattern class diagram

This pattern has the following parts:

· Abstract product

· Concrete product

· Abstract creator

· Concrete creator

· Client

The pattern’s benefits are as follows:

· Uses abstracts factories of like interfaces

· Enables the interchanging of product families

It also has this drawback:

· Introducing a new product is difficult.

A Comprehensive Look

The Abstract Factory pattern is an extension of the Factory Method pattern in that it uses many factory methods to create a subset, or related grouping of products. These product sets can then become interchangeable with other sets. This is due to the factory’s polymorphism, established by the abstraction to the factory. The purpose of the Abstract Factory pattern is to group products, often of varying types. In a nutshell, an abstract factory is a collection of factory methods whose collective products work together.

The abstract factory conceals the concrete objects it instantiates by concerning itself with the product interfaces. For extensibility, the Abstract Factory pattern defers the manufacturing of objects to subclasses. This lets the caller of the request remain unfamiliar with particulars beyond those of the abstractions in use: the abstraction of the factory and the abstractions of any products the factory returns.

The factory’s abstraction declares the interface that subclasses must implement. As the base class for all like-minded factories, the interfaces of all products used are exposed via the appropriate factory methods. As the Factory Method pattern states, the name of each method should describe the creation of the product. Often, the create, get, and make prefixes are used to help developers who are familiar with this pattern identify its existence in the code.

The factory’s subclass has a different role to accompany the superclass. The subclass knows which concrete products are created and conceals this knowledge from the system, including its own abstraction. With the Abstract Factory pattern, each product is realized at author time; therefore, the methods don’t require conditional logic. Rather than use a conditional statement to determine a product, a conditional statement determines the factory to use.

The client—the factory’s messenger—uses each set of products via the appropriate factories as needed.

Vignette

A fast-food restaurant decided to increase its sales by adding a new breakfast sandwich to its menu. The sandwich contained eggs, cheese, bacon, and sausage. When a customer ordered, they had the option of choosing a specific type for each of the ingredients offered. The choices were as follows:

· Egg: Free-range, egg substitute, egg whites, or regular

· Cheese: Cheddar, Swiss, asiago, or muenster

· Bacon: Veggie, regular, Canadian, or turkey

· Sausage: Country, original, English, or vegetarian

Unfortunately, the fast-food restaurant wasn’t delivering quick service. People liked the food—but the number of options slowed the ordering process as well as preparation time, and instead of increasing sales, caused customers to leave due to the long wait. Rather than continue to allow the delay between when the customer ordered and when they received their food, the franchise decided to narrow the options available. To do this, it picked the four most popular combinations of ingredients and offered four different breakfast sandwich options. The new selections were as follows:

· Product A: Egg whites, asiago cheese, turkey bacon, English sausage

· Product B: Egg substitute, muenster cheese, veggie bacon, vegetarian sausage

· Product C: Egg, cheddar cheese, regular bacon, original sausage

· Product D: Free-range egg, Swiss cheese, Canadian Bacon, country sausage

After the four new items were introduced to the public, wait times decreased due to more rapid ordering. However, the restaurant’s wait times were still significantly longer than those of fast-food competitors. This was due to the new routine in the kitchen. Preparing items that had previously been on the menu had become second nature to the employees. But the staff were unfamiliar with the new sandwiches and had to put more thought and time into their preparation. Even though each refrigerator drawer was labeled with an ingredient—cheese, sausage, bacon, and so on—employees had to recall and differentiate options every time they made a sandwich.

The company created a new solution to quickly decrease preparation time and improve sales. Modifying the kitchen organization, the restaurant designated a drawer for each specific sandwich:

· Drawer 1: Product A

· Drawer 2: Product B

· Drawer 3: Product C

· Drawer 4: Product D

By organizing a set of ingredients per product, all the employees needed to know was which drawer to use.

The AS3 Cast

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

· Abstract creator: The exposed interface, as well as the base factory. Defines the interface that an interchangeable set of factories can message, and defines the abstract products to be used in the factory. A factory can perform nearly any creational operation needed for a class:

· Initialize

· Pull in data

· Configure

· Set states

· Concrete creator: A factory subclass that contains the logic necessary to instantiate the appropriate object in a genus of products expected by the superclass for each factory method declared in the superclass.

· Abstract product: A product genus that exposes the interface that all concrete products of the given genus inherit.

· Concrete product: The physical object that can be instantiated. Extends the abstract product to express itself as a member of the type to be used in the logic of the creator.

· Client: The messenger of the abstract factory. Can be any aspect of the application or system that has prior knowledge of the abstract products as well as the abstract factory that is in use.

When It’s Useful

The Abstract Factory pattern is useful in the following situations:

· When similar items have a reason to vary

· When you need to localize appropriate objects into a set

· When you need to add a layer of abstraction among products

Example

The Abstract Factory pattern relies on a uniform abstraction among different factories. This allows a factory to be parameterized and remain abstract to the code that uses it. The uniformity ensures that although each factory’s implementation may vary, the product returned is that of a specific type.

You can see the benefit of using an abstraction with multiple factories in the overlay example. Suppose you’re informed that the overlays you created are suitable only if the user comes from a particular coast. Because the United States has two coasts, you need another set of overlays that reflect the opposite coast. This value is passed in as a variable from PHP at load time.

Listing 6-12 revisits the code used in the Simple Factory example that showed the logic to create an overlay. The problem you now face is the need to create an appropriate set of products that can be interchanged depending on which coast a user comes from.

Listing 6-12. Simple Factory demonstrating the encapsulation of creational logic

public function createOverlay( overlayType : String ) : Overlay
{
var currentOverlay : Overlay;

switch(overlayType)
{
case SectionEvent.VIDEO_OVERLAY:
currentOverlay = new VideoOverlay();
break;
case SectionEvent. PHOTO_OVERLAY:
currentOverlay = new PhotoViewer();
break;
case SectionEvent.AUDIO_OVERLAY:
currentOverlay = new AudioOverlay();
break;
case SectionEvent.TWITTER_OVERLAY:
currentOverlay = new TwitterOverlay();
break;
case OverlayEvent.TWITTER_SUBMIT_OVERLAY:
currentOverlay = new AddTweetOverlay();
break;
case OverlayEvent.NEW_FORM_OVERLAY:
currentOverlay = new NewFormOverlay();
break;
}
return currentOverlay;
}

The code in Listing 6-12 uses conditional logic to determine which overlay is necessary at runtime by using string parameterization. This determination is due to the unknown object that is required at runtime.

The Abstract Factory pattern, on the other hand, uses any number of factory methods to create a complete set of products. For this reason, conditionals are often unnecessary. Additionally, because the Abstract Factory pattern uses product sets, products can vary in type in the factory abstraction. In other words, two factory methods of different types can be used in an abstract factory.

Listing 6-13 shows an abstract class that acts as a template for every subclass. Note how the overlays, which previously were called in one operation, have been refactored into their own factory methods.

Listing 6-13. An abstract class ensures uniformity among subclassed factories

package
{
public class
{
public function createPhotoViewerOverlay() : APhotoOverlay
{
var photoViewer : APhotoOverlay = makePhotoOverlay();
return photoViewer;
}

public function createVideoOverlay() : AVideoOverlay
{
var video : AVideoOverlay = makeVideoOverlay();
return video;
}

public function createAudioOverlay() : AAudioOverlay
{
var audio : AAudioOverlay = makeAudioOverlay();
return audio;
}

public function createTwitterOverlay() : ATwitterOverlay
{
var tweet : ATwitterOverlay = makeTwitterOverlay();
return tweet;
}

public function createFormOverlay() : AFormOverlay
{
var form : AFormOverlay = makeFormOverlay();
return form;
}

private function commonDisplayObjectPrep( dO : DisplayObject ) : DisplayObject
{
var currentOverlay : DisplayObject = dO as DisplayObject;

currentOverlay.y = SiteConfig.HEADER_HEIGHT;
currentOverlay.addEventListener( OverlayEvent.CLOSE_OVERLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.INTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.OUTRO_COMPLETE , handleEvent );
currentOverlay.addEventListener( OverlayEvent.PLAY , handleEvent );
currentOverlay.addEventListener( OverlayEvent.SUBMIT_TWEET , handleEvent );

currentOverlay.addEventListener( OverlayEvent.TWITTER_SUBMIT_OVERLAY ,
image handleEvent );

return currentOverlay;
}

protected function makePhotoOverlay() : APhotoOverlay
{
}

protected function createVideoOverlay() : AVideoOverlay
{
}

protected function createAudioOverlay() : AAudioOverlay
{
}

protected function makeTwitterOverlay() : ATwitterOverlay
{
}

protected function makeFormOverlay() : AFormOverlay
{
}
}
}

Now each coast has its own factory. You do this by subclassing the abstract class AbstractFactoryCoastOverlaySets and applying the appropriate implementations per coast. This allows each factory to specify how each product is returned and localizes the code related to each coast.

Note the inclusion of the private method commonDisplayObjectPrep. This example shows that you can maintain a common preparation if all returned products require similar preparations. Otherwise, each product can also have its own prep work before it’s returned to the client. This is acceptable because types are often different in an abstract factory.

Listing 6-14. West-coast overlays

package
{
public class WestCoastOverlaySet extends AbstractFactoryCoastOverlaySets
{
override protected function makePhotoOverlay() : APhotoOverlay
{
return new WestCoastPhotoOverlay();
}

protected override function makeVideoOverlay() : AVideoOverlay
{
return new WestCoastVideoOverlay();
}

protected override function makeAudioOverlay() : AAudioOverlay
{
return new WestCoastAudioOverlay();
}

protected override function makeTwitterOverlay() : ATwitterOverlay
{
return new WestCoastTwitterOverlay();
}

protected override function makeFormOverlay() : AFormOverlay
{
return new WestCoastFormOverlay();
}
}
}

Listing 6-15. East-coast overlays

package
{
public class EastCoastOverlaySet extends AbstractFactoryCoastOverlaySets
{
override protected function makePhotoOverlay() : APhotoOverlay
{
return new EastCoastPhotoOverlay();
}

protected override function makeVideoOverlay() : AVideoOverlay
{
return new EastCoastVideoOverlay();
}

protected override function makeAudioOverlay() : AAudioOverlay
{
return new EastCoastAudioOverlay();
}

protected override function makeTwitterOverlay() : ATwitterOverlay
{
return new EastCoastTwitterOverlay();
}

protected override function makeFormOverlay() : AFormOverlay
{
return new EastCoastFormOverlay();
}
}
}

By decoupling the return types from Overlay to that which each overlay generalizes, you give the compiler more control over your author-time bindings. Now all you need are abstract classes for each of product.

With two factories in your system, you need to know which factory to instantiate. Listing 6-16 uses a simple factory to determine which factory should be used in the application. You use a simple factory rather than an abstract factory because there are only two coasts, and I don’t foresee any change occurring here.

Listing 6-16. CoastOverlayLogic is a simple factory that determines the appropriate coast factory

package
{
public class CoastOverlayLogic
{
private const WEST_COAST:String='west_coast';
public function CoastOverlayLogic()
{
}

public function createOverlayPreparation( coast : String ) :
image AbstractFactoryCoastOverlaySets
{
switch(coast)
{
case WEST_COAST:
return new WestCoastOverlaySet();
break;
default:
return new EastCoastOverlaySet();
break;
}
return null
}
}
}

To illustrate how you can add another factory, let’s suppose you also need a factory for Canada. You can create another subclass as shown in Listing 6-17 and Listing 6-18.

Listing 6-17. Canadian overlays

package
{
public class CanadaOverlaySet extends AbstractFactoryCoastOverlaySets
{
override protected function makePhotoOverlay() : APhotoOverlay
{
return new CanadaPhotoOverlay();
}

protected override function makeVideoOverlay() : AVideoOverlay
{
return new CanadaVideoOverlay();
}

protected override function makeAudioOverlay() : AAudioOverlay
{
return new CanadaAudioOverlay();
}

protected override function makeTwitterOverlay() : ATwitterOverlay
{
return new CanadaTwitterOverlay();
}

protected override function makeFormOverlay() : AFormOverlay
{
return new CanadaFormOverlay();
}
}
}

Listing 6-18. CoastOverlayLogic reflects the addition of Canada

package
{
public class CoastOverlayLogic
{
private const WEST_COAST : String = "west_coast";
private const EAST_COAST : String = "east_coast";
private const CANADA : String = "canada";

public function CoastOverlayLogic()
{
}

public function createOverlayPreparation( coast : String ) :
image AbstractFactoryCoastOverlaySets
{
switch(coast)
{
case WEST_COAST:
return new WestCoastOverlaySet();
break;
case EAST_COAST:
return new EastCoastOverlaySet();
break;
case CANADA:
return new CanadaOverlaySet();
break;

default:
return null;
break;
}
}
}
}

FAQ

· What distinguishes this from the Factory Method pattern?

The Abstract Factory pattern differs from the Factory Method pattern in that it offers a set of products to be manufactured. The Factory Method pattern returns only one product.

· This pattern sounds awfully like the Factory Method pattern with extra products.

The diagram does look a lot like the Factory Method pattern. The difference is that a factory method uses an abstraction with no need for interchangeability in the system, but rather for extensibility. This lets you add a new product to a subclass and use it in your application by overriding a hook.

Because the factory method returns a product of the same type, the logic of the factory can use a conditional statement to return the instance that is required to meet the goals of the system.

In the Abstract Factory pattern, the factory object can be made up of numerous factory methods, but this isn’t the important aspect. This pattern focuses on the parameterization of a series of sets. Factories can be swapped out with other factories of product sets to meet given criteria.

· It appears that product preparation can extensively elongate the abstract class.

This is true and worth keeping in mind. The preparations should remain small enough to work with; otherwise, they may be difficult to maintain and likely to change. As you know, everything can change, so you should be proactive about keeping this code manageable. But if it begins to become unmanageable, it’s all right—the next pattern can work with the Abstract Factory pattern for this reason.

Related Patterns

The following patterns are related to the Abstract Method pattern:

· Builder

· Factory

· Template Method

The Builder Pattern

The Builder pattern separates the construction steps from the product to offer flexibility among product representations. Figure 6-4 shows the class diagram.

image

Figure 6-4. Builder pattern class diagram

This pattern has the following parts:

· Abstract product

· Concrete product

· Abstract builder

· Concrete builder

· Abstract director

· Concrete director

· Client

The pattern’s benefits are as follows:

· Very high level of control over object creation

· Enables varying products from the same algorithms

· Conceals the construction process from the client

A Comprehensive Look

The Builder pattern is concerned with building objects in a manner that promotes interchangeability in the way a product is represented. Through composition and delegation, a client messages the builder with the instructions to build or return the product it requires.

The Builder pattern conceals several operations that may be involved in achieving the final representation of a product expected by the client. This makes the Builder pattern more intricate than its similar Factory colleagues. A builder can create complex objects that require more than a simple initialization, configuration, or assembly. Because a concrete builder focuses on the creation of a final product, it offers a higher level of attention to the assembly of its creation.

A concrete builder has the methods needed to create such a complex product but uses them only when messaged. This lets you manipulate the inner workings that may affect the appearance of the product.

The director takes a request from the client and uses it in a sequence of actions between the builder and itself in an effort to arrive at a final product.

Because the details of the construction are hidden from the client, the final representation of the product may remain abstract to the system. The implementation of the builder that constructs the product is flexible because its implementations are separate from that of its superclass.

Because a concrete builder subclasses an abstraction, an additional layer of abstraction can be introduced into the client, much like in the Abstract Factory pattern. Due to the advanced construction the Builder pattern offers, many of the products returned are composites: objects composed of one or more like objects.

Vignette

Burger Kind’s has used the slogan “Your Way Right Away” for years. When you walk up to the counter, you ask for a cheeseburger, expecting the cook to ask, “How would you like the meat cooked?” Unfortunately, that doesn’t happen; and before you realize that you have to ask up front for your desired preparation, the employee behind the counter hands you a packaged meal. Opening it, you find a charred patty dressed with mayonnaise and mustard. Yuck. These are things you would have asked not to have, had you known they were standard.

Disgusted with your lunch, you walk over to SubWeight. An employee greets you, much like at Burger Kind, and asks if they may take your order. Realizing your earlier mistake of keeping silent, you tell them everything you want up front. “I would like a tuna sandwich toasted on wheat with olives, onions, lettuce, black pepper, salt, jalapenos, and Swiss cheese,” followed by a “please” to be courteous. The employee stares at you as if you’re doing something improper. This is your first time at SubWeight, so you’re unaware of their process.

The workstation shows everything available so that as your sandwich is prepared, you can oversee the process during which your sandwich is crafted. Genius: they’re sandwich artists—or rather, you are.

It all begins with bread. They have a decent selection to choose from: wraps, wheat, Italian, and more. All you have to do is say “Foot-long wheat.” Having the base on which to add your ingredient objects, the employee asks, “What kind of cheese?” And you answer, “Swiss.” This process continues step by step, allowing you to specify the preparation to your liking. Because SubWeight offers you a say in the assembly of your sandwich, you can ask three times for more lettuce, before moving on to the next ingredient.

Finally, the employee asks if there will be anything else, signifying the end of your product’s creation. Via a “No” command, you can have your sandwich returned. Then you turn over delivery to the client: your stomach.

The AS3 Cast

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

· Abstract builder: Defines an interface that lets the director have a contract between itself and the builder. Because the builder object doesn’t assemble itself, the abstract builder shouldn’t have any implementations declared. And because the abstract builder doesn’t have any default implementations, it’s also safe to use an interface for the concrete builder. However, if you have concrete builders that share similar data, an abstract builder is a good idea.

· Concrete builder: Contains the implementations of its defined interface. Although it contains the implementations to make a product, the builder doesn’t try to build the product itself. Instead, it takes directions from the named object: the director.

· Abstract director: Contains the instructions to create the final product using the builder object’s interface. Because this vision may vary among products, the abstract director provides the flexibility that lets similar directors remain uniform.

· Concrete director: Encapsulates the logic to conceal the steps of product creation from the client. This separation of details from interface lets you introduce interchangeable logic, from which new representations of a product may result.

· Abstract product: Exposes the interface that all concrete products of the given genus inherit. In a few textbooks the abstract product is lacking, because, many times, the product returned is so specific and unlike other products that the builders create. Your goal isn’t to program to concretes, but to an interface, and therefore you need either an abstract class or an interface for the product.

· Concrete product: Extends the abstract product to express itself as a member of the type to be used by the client. Often this product is a composite that requires many steps to construct.

· Client: The messenger of the builder. It can be any aspect of the application or system that has prior knowledge of the abstract products, as well as the abstract factory being used.

When It’s Useful

The Builder pattern is useful in the following situations:

· When you’re using third-party APIs

· With factories, to help with complicated preparations

· When you’re constructing composites

Example

The best thing about the Builder pattern is its ability to create numerous representations from a given pool of resources. This is an amazing behavior to have in RIA development. Imagine purchasing Lego blocks in bulk on eBay. Depending on how many Legos you have, you may be able to make several different structures from only six basic shapes.

You can create so many different formations thanks to your imagination. The pieces don’t change, but your ideas do, and because of this you can vary your representations even though you’re using the same blocks.

This pattern is very common in AS3, especially as applications have grown larger and more complex. Display objects and display object containers become composites and vary from scene to scene. But a builder isn’t just for composites, and that too makes it special.

The following example uses a recognizable game to simulate the advantage of the Builder design pattern. The image in Figure 6-5 is the final product created by the collaboration between a director and builder. Listing 6-19 through Listing 6-24 show the code used. It all begins with an interface.

image

Figure 6-5. Stage 1-0 of a game

Listing 6-19. AbstractMarioEsqueLevelEditor defines the interface of the builder

package
{
public class AbstractMarioEsqueLevelEditor
{
private var _bitmap : BitmapData;
private var _backgroundColor : uint;
private var _width : int;
private var _height : int;
private var _pt : Point;
private var _tile : Shape;

public function AbstractMarioEsqueLevelEditor()
{
_tile = new Shape();
_pt = new Point( 0 , 0 );
}

final public function createMap() : void
{
bitmap = doCreateMap();
}

final public function getLevel() : BitmapData
{
return _bitmap;
}

final public function createStone( rect : Rectangle ) : void
{
addTile( doCreateStone() , rect );
}

final public function createSolidBrick( rect : Rectangle ) : void
{
addTile( doCreateSolidBrick() , rect );
}

final public function createBreakableBrick( rect : Rectangle ) : void
{
addTile( doCreateBreakableBrick() , rect );
}

final public function createMoneyBox( rect : Rectangle ) : void
{
addTile( doCreateMoneyBox() , rect );
}

final public function createCloud( rect : Rectangle ) : void
{
addTile( doCreateCloud() , rect );
}

final public function createHill( rect : Rectangle ) : void
{
addTile( doCreateHill() , rect );
}

final public function createBush( rect : Rectangle ) : void
{
addTile( doCreateBush() , rect );
}

final public function createCastle( rect : Rectangle ) : void
{
addTile( doCreateCastle() , rect );
}

final public function createPipe( rect : Rectangle ) : void
{
addTile( doCreatePipe() , rect );
}

final public function get width() : int
{
return _width;
}

final public function set width( width : int ) : void
{
_width = width;
}

final public function get height() : int
{
return _height;
}

final public function set height( height : int ) : void
{
_height = height;
}

final public function get backgroundColor() : uint
{
return _backgroundColor;
}

final public function set backgroundColor( backgroundColor : uint ) : void
{
_backgroundColor = backgroundColor;
}

final public function get bitmap() : BitmapData
{
return _bitmap;
}

final public function set bitmap( bitmap : BitmapData ) : void
{
_bitmap = bitmap;
}

protected function doCreateMap() : BitmapData
{
return new BitmapData( width , height , false , backgroundColor );
}

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

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

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

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

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

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

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

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

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

private function addTile( dO : DisplayObject , rect : Rectangle ) : void
{
var sprite : BitmapData = snapShot( dO );
_pt.x = rect.x;
_pt.y = rect.y;
if (rect.width > 0 || rect.height > 0)
{
sprite = tile( sprite , rect );
}
bitmap.copyPixels( sprite , sprite.rect , _pt );
}

private function snapShot( dO : DisplayObject ) : BitmapData
{
var snapshot : BitmapData = new BitmapData( dO.width, dO.height, true, 0 );
snapshot.draw( dO );
return snapshot;
}

private function tile( bmpd : BitmapData , rect : Rectangle ) : BitmapData
{
var _t : Shape = _tile;
var g : Graphics = _t.graphics;
g.clear();
g.beginBitmapFill ( bmpd , null , true , false );
g.drawRect( 0 , 0 , rect.width , rect.height );
g.endFill();
return snapShot( _t );
}
}
}

Having provided the abstract class, you proceed to fulfill the specifics of the factory methods involved via the subclass. You call this MarioLevelEditor (see Listing 6-20).

Listing 6-20. MarioLevelEditor subclasses AbstractMarioEsqueLevelEditor to supply its implementation

package
{
public class MarioLevelEditor extends AbstractMarioEsqueLevelEditor
{
public function MarioLevelEditor()
{
super();
}

override protected function doCreateSolidBrick() : DisplayObject
{
return new SolidBrick();
}

override protected function doCreateBreakableBrick() : DisplayObject
{
return new BreakableBrick();
}

override protected function doCreateStone() : DisplayObject
{
return new Stone();
}

override protected function doCreateMoneyBox() : DisplayObject
{
return new MoneyBox();
}

override protected function doCreateCloud() : DisplayObject
{
return new Cloud();
}

override protected function doCreateHill() : DisplayObject
{
return new Hill();
}

override protected function doCreatePipe() : DisplayObject
{
return new Pipe();
}

override protected function doCreateBush() : DisplayObject
{
return new Shrubs();
}
}
}

The interface in Listing 6-19 is extensive and would be a pain to modify in a client, if the interface changed. To ease the burden this would cause, you create a middleman—the director—that knows about the given interface exposed by the builder (see Listing 6-21). A director adheres to the interface of an abstract builder and greatly minimizes the interface that a client must be concerned with. Of course, each director may change to provide different implementations; therefore you need to provide a superclass to promote polymorphism while also implementing code common to each subclass.

Listing 6-21. AbstractMarioLevelDirector

package
{
public class AbstractMarioLevelDirector
{
protected var _builder : AbstractMarioEsqueLevelEditor;

public function AbstractMarioLevelDirector( builder :
image AbstractMarioEsqueLevelEditor )
{
_builder = builder;
}

public function getLevel() : BitmapData
{
return _builder.getLevel();
}
}
}

With the abstract director in place, you can begin creating implementations in your subclasses. Each implementation controls the representation of the product. You do this by deferring all requests to the passed-in reference of a builder object.

Listing 6-22. LevelOne subclasses AbstractMarioLevelDirector

package
{
public class LevelOne extends AbstractMarioLevelDirector
{
private const _width : int = 400;
private const _height : int = 300;
private var rect : Rectangle = new Rectangle( 0 , 0 , 0 , 0 );

public function LevelOne( builder : AbstractMarioEsqueLevelEditor )
{
super( builder );
}

public override function getLevel() : BitmapData
{
_builder.width = _width;
_builder.height = _height;
_builder.backgroundColor = 0x0000FF;
_builder.createMap();
buildPipes();
buildFloor();
buildScenicBushes();
buildClouds();

buildMoneyBox();
buildScenicBricks();
return _builder.getLevel();
}

private function buildScenicBushes() : void
{
assignRect( 100 , _height - 28 * 2 - 32 );
_builder.createBush( rect );
}

private function buildMoneyBox() : void
{
assignRect( 50 , _height - 51.25 - 95 );
_builder.createMoneyBox( rect );
}

private function buildScenicBricks() : void
{
assignRect( 50 - 28 , _height - 51.25 - 95 );
_builder.createBreakableBrick( rect );
assignRect( 50 + 28 , _height - 51.25 - 95 );
_builder.createBreakableBrick( rect );
}

private function buildPipes() : void
{
assignRect( 250 , _height - 28 * 2 - 65 );
_builder.createPipe( rect );
}

private function buildFloor() : void
{
assignRect( 0 , _height - 56 , _width , _height - 56 );
_builder.createSolidBrick( rect );
}

private function buildClouds() : void
{
assignRect( 0 , 40 );
_builder.createCloud( rect );
assignRect( 200 );
_builder.createCloud( rect );
}

private function assignRect( x:int = 0, y:int = 0, w:int = 0, h:int = 0 ) : void
{
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;
}
}
}

With the builder and director complete, its time to put them to use, as demonstrated in Listing 6-23.

Listing 6-23. DocumentClassinstantiates both director and builder to produce your Level

package
{
public class DocumentClass extends Sprite
{
private var _bitmap : Bitmap;

public function DocumentClass()
{
var stg : Stage = this.stage;
stg.scaleMode = StageScaleMode.NO_SCALE;
stg.align = StageAlign.TOP_LEFT;
var levelEditor : AbstractMarioEsqueLevelEditor = new MarioLevelEditor();
var director : AbstractMarioLevelDirector = new StageTwo( levelEditor );
// LevelOne(levelEditor);
_bitmap = new Bitmap( director.getLevel() );
addChild( _bitmap );
}
}
}

Because the builder can’t build the product without directions from the director, you can create numerous variations from the same builder resources. Suppose you want to adjust the product representation as shown in Figure 6-6 (see also Listing 6-24).

image

Figure 6-6. A different representation of Stage 1-1

Listing 6-24. StageTwo is a director subclass with a different set of implementations

package
{
public class StageTwo extends AbstractMarioLevelDirector
{
private const _width : int = 400;
private const _height : int = 300;
private var rect : Rectangle = new Rectangle( 0 , 0 , 0 , 0 );

public function StageTwo( builder : AbstractMarioEsqueLevelEditor )
{
super( builder );
}

public override function getLevel() : BitmapData
{
_builder.width = _width;
_builder.height = _height;
_builder.backgroundColor = 0x0000FF;

_builder.createMap();
buildPipes();
buildFloor();

buildClouds();
buildStairs();
return _builder.getLevel();
}

private function buildMoneyBox() : void
{
assignRect( 50 , _height - 51.25 - 95 );
_builder.createMoneyBox( rect );
}

private function buildStairs() : void
{
var totalWide : int = _width;
var floorTall : int = _height - 28 * 2;
var row : int = 6;
var col : int = 1;
while (--row)
{
var dist : int = totalWide - row * 28;
assignRect( dist , floorTall - col * 28 , row * 28 , 28 );
_builder.createStone( rect );
col++;
}
}

private function buildPipes() : void
{
assignRect( 50 , _height - 28 * 2 - 65 );
_builder.createPipe( rect );
}

private function buildFloor() : void
{
assignRect( 0 , _height - 56 , _width , _height - 56 );
_builder.createSolidBrick( rect );
}

private function buildClouds() : void
{
assignRect( 0 , 40 );
_builder.createCloud( rect );
assignRect( 40 , 40 );
_builder.createCloud( rect );
assignRect( 400 , 30 );
_builder.createCloud( rect );
}

private function assignRect( x:int = 0, y:int = 0, w:int = 0, h:int = 0 ) : void
{
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;
}
}
}

The builder allows variations among internal representations. Each director can use a builder as it sees fit.

FAQ

· You could use the stage in Flash to do the same thing, probably much faster. What makes this approach any better?

The example certainly could be created on the stage. The example demonstrates varying representations, which is far easier to do with graphics than with internal data. The focus of the example is the sequence of steps the director follows to vary the representation of the product.

Although you may be able to re-create this example on the stage more quickly, you wouldn’t be able to do so if there were no graphics involved to place at author-time.

Imagine an RIA that allows a user to create a FLV reel from any number of provided FLVs. Users can cut and stitch the FLVs into a seamless .flv file that they can download. Using a builder with the exposed methods to cut and stitch bytes together, you can use the director to reflect the users’ choices.

There are many additional reasons to use a Builder design pattern.

· The example varies the representation using common assets. Can each concrete builder change those assets?

This example bundles your assets in one .swc file for simplicity, but the truth is that you should only use what you know you need. This reduces file sizes and limits excess files.

When you’re using the Builder pattern, each concrete builder can introduce its own assets by overriding factory methods. If there are many assets that require variation, you can use abstract factories as well.

· What is another reason to use a builder?

Suppose you were refactoring the code shown in Listing 6-25. This code is very rigid and shows what often occurs when there is uncertainty about how to uniformly modify the preparations among a series of objects and their varying attributes. The Builder pattern would be a great aid in adding uniformity and abstracting the assembly in the code.

Listing 6-25. Logic and preparation tied together

override public function createProduct( string : String ) : DisplayObject
{
switch(string)
{
case STARTUP_SCREEN:
currentClass = new SystemStartup();
currentClass.x = (System.SECTION_WIDTH) * .5 - 70 - 4;
currentClass.y = 103.5 - 70;
currentClass.nextState = VIDEO_WELCOME;
return currentClass;
break;
case VIDEO_WELCOME:
currentClass = new Introduction();
currentClass.x = 835 - 5;
currentClass.y = 55;
currentClass.nextState = CLEARANCE_SCREEN;
return currentClass;
break;
case DEMONSTRATION_SCREEN:
currentClass = new Demonstration();
currentClass.x = 835 - 4;
currentClass.y = 75;
currentClass.nextState = NULL_SCREEN;
return currentClass;
case NULL_SCREEN:
currentClass = new NullState();
currentClass.x = (1600 - currentClass.width) * .5 - 4;
currentClass.y = (600 - currentClass.height) * .5;
currentClass.nextState = NULL_SCREEN;
return currentClass;
break;
}
}

Note: Here’s a hint to get you on your way toward refactoring Listing 6-25: use four builders, one director, and one factory method.

Related Patterns

The following patterns are related to the Builder pattern:

· Factory Method

· Template Method

· Abstract Factory

The Simple Singleton Pattern

The Simple Singleton pattern provides a global reference to an object that requires uniqueness. Figure 6-7 shows the class diagram.

image

Figure 6-7. Simple Singleton pattern class diagram

This pattern has the following parts:

· Concrete singleton

· Class member

· Client

The pattern’s benefits are as follows:

· Grants global access to an object

· Maintains access to its unique instance

· Is easy to create

It also has this drawback:

· Can’t be extended (change is a constant)

A Comprehensive Look

Chapter 4 explained that not all object-oriented languages are built equally, and therefore not all patterns can be implemented equally. For this reason, a design pattern’s intentions must be taken into consideration when you implement that pattern. Because the Simple Singleton pattern’s intentions can’t be met in the ActionScript 3 language simply by using the static modifier, you can’t, and shouldn’t, consider the standard implementation of the Simple Singleton an AS3 design pattern.

The intentions of the Simple Singleton design pattern are as follows:

· It ensures that only one instance of an object is in use.

· It must contract an access point that the one instance has acquired.

· The singular instance should have the flexibility to offer change without adding more namespaces to the system.

But creating a singleton using the static keyword achieves only the first two of these three intentions. This is why I refer to this implementation as Simple Singleton, because it intends to maintain a global reference to a given object.

Ensuring global access for an instance requires the instance to be a class member. You learned in Chapter 2 that in order to access a class member, you must access the value from the Class object itself. Therefore, it’s safe to assume there are many references to a concrete class strewn throughout the code of a system that references the member. This nearly guarantees that any change you make to the object occurs as a modification rather than an extension.

The only other remaining solution would be to track down every occurrence of the static reference and replace it with another static instance. You can see how that might force developers into breaking the open-closed principle (open for extension, closed for modification). This inflexibility is, again, why I call this implementation Simple Singleton and say that it isn’t a design pattern in AS3.

Vignette

A southern brand of fried chicken is regarded by locals as the world’s best chicken. This gives the proprietor of the restaurant an idea. He wants his chicken to be eaten by everyone, not just people in the local vicinity. Certain that he can’t get the entire world to come to his town, the proprietor decides to bring his variety of chicken to the world. He wants to be known globally and have his specialty chicken within reach of any consumer.

Knowing that his chicken will never change, he packages it and ships it to a global supermarket chain. Anyone who wants a taste of this chicken now has global access to it. The prepackaged chicken, made by the original chef, ensures great taste each and every time. The packaging helps to ensure this, with its fancy ability to lock in freshness. And the chef was required to sign an exclusive contract with the supermarket, ensuring that the chicken will always be available for clients.

The chef’s chicken does so well that he receives letters from around the world asking him to create an alternate product to promote a healthy diet. The chef works to extend his already famous product, and the result is grilled chicken.

Grilled chicken provides a much healthier alternative to the original chicken. Excited by the opportunity this offers the world, the chef wants to supply the new product in place of the original chicken. Unfortunately, the contract specifies that stores have exclusive rights of the chef’s original recipe, and no substitutions can be made—the supermarkets are making a tremendous profit.

The chef really wants the world to experience his new chicken variety, and he considers putting the new chicken in the old packaging. This way, people would experience the chicken, remain happy, and benefit from the healthier recipe. Unfortunately, this approach would also cause confusion: some people might receive the original recipe while others got the new recipe, and this might make the product appear inconsistent.

Unwilling to change a good thing, the chef signs another contract with the supermarket. Instead of swapping the new product for the previous one, he now offers two products. The chef can take consolation in knowing that neither product will change.

The AS3 Cast

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

· Concrete instance: The object of a singular instance. All instances can be instantiated and have their data modified via an object using the expressed interface. The concrete instance has a unique method that acts as a wrapper around a class member instance.

· Class member Instance: A reference associated with the class and not the object. This reduces memory allocation given any number of instances of a given class. Although it’s public, a class member can be accessed in a manner that doesn’t require an instance. You achieve such a class reference by using the static modifier.

· Client: The simple singleton’s messenger. The client can be any aspect of the application or system that has prior knowledge of the abstract product. It also must know the fully qualified name of the static class and its static method.

Example

The Simple Singleton pattern is regularly used in large-scale projects. What makes this particular object work is also the reason it’s not a design pattern for AS3. The only way you can get the instance as a global variable and/or prevent a unique instance from any other instantiation from overwriting such a reference is to make the reference a class member. As you learned in Chapter 2, class members can only be accessed via the fully qualified class name.

The convenience of the singleton object explains why it continues to flourish. But as you’ll soon see, and likely will agree, the Simple Singleton approach may not be as helpful as you think.

A simple singleton is also used as a means of achieving a goal, by providing global reach from one object’s namespace to another. Generally, it’s used to communicate with a major portion of a shell or model for things such as sound management or tracking.

The code in Listing 6-26 is an excerpt of a class from an RIA that lets you use a user’s Facebook profile throughout the application. Currently, the user’s profile is only accessible to the current class. This is because the RIA was never intended to remember the user’s information. The current class was intended to let users share the application’s link with their friends while displaying a message to the user who used their profile.

Listing 6-26. FaceBooklogin

package
{
public class FaceBookLogin extends EventDispatcher
{
protected var _faceBook : IFaceBook;
protected var _shortProfile : ShortProfileInformation;
private var _hasProfile : Boolean = false;
private var _ready : Boolean;

public function FaceBookLogin( target : IEventDispatcher = null )
{
super( target );
_ready = false;
_shortProfile = new ShortProfileInformation();
}

public function init() : void
{
_ready = false;
// a class that uses my FaceBookGraphAPI;
_faceBook = new FaceBookFacade();

_faceBook.addEventListener( FacebookEvent.CONNECT , faceBookConnectHandler ,
image false , 0 , true );
}

public function get facebook() : IFaceBook
{
return _faceBook;
}

public function get hasProfile() : Boolean
{
return _hasProfile;
}

public function get shortProfile() : ShortProfileInformation
{
return _shortProfile;
}

protected function faceBookConnectHandler( event : FacebookEvent ) : void
{
if (event.success)
{
FacebookCall( _faceBook.queryUserInformation() ).addEventListener(
image FacebookEvent.COMPLETE , userInfoLoaded );

dispatchEvent( new FacebookEvent( FacebookEvent.CONNECT, false, false ) );
}
}

protected function userInfoLoaded( event : FacebookEvent ) : void
{
var aFaceBookCall : FacebookCall = event.target as FacebookCall;
aFaceBookCall.removeEventListener( FacebookEvent.COMPLETE , userInfoLoaded );

dispatchEvent( new FacebookEvent( FacebookEvent.COMPLETE , false , false ) );

var profile : ProfileInformation = _faceBook.getUserProfile();
_shortProfile.usrIdentifier = profile.userName;
_shortProfile.faceBook = true;
_hasProfile = true;
}
}
}

The Simple Singleton pattern offers a solution to the problem at hand. How can you capture the information in this class so it remains usable throughout the site, as well as update current text fields with parts of a user’s profile? A simple singleton lets you acquire user data globally, while ensuring that the results remain unchanged. To do this, you use a class member to keep a pointer to the memory of the object’s instantiation. This allows you to obtain all methods via the interface of the object when it’s retrieved from the class. It’s appropriate to have Facebook information inFaceBookClass, so you create a static variable to reference the pointer:

public static var _fbReference:FaceBook;
// This class member will hold any subclass of Facebook

The static attribute of the reference enables global access to the class by way of its Class object. You set the static attribute to a variable rather than a constant so its pointer can be manipulated:

FaceBook.fbReference = new FaceBook();
//this changes the previous pointer to that of a new Facebook initialization.

To limit an object’s ability to modify _fbReference, you declare the static variable as being private in scope, and use a getter for outside objects to obtain the reference. The problem is that now you can’t subclass the FaceBook object and set the variable with the extension. So, you set the access modifier to protected, the better option. This allows your object to use the static reference because it’s in the same hierarchy. This also means that if another FaceBook object is instantiated, it’s granted appropriate privileges to overwrite the static reference, because it also has access to that variable.

You need to ensure that the FaceBook instance occurs one time and one time only; otherwise your information can and will be overwritten. The Simple Singleton pattern offers a solution to needing an access point that the class checks if an instance exists. If an instance has already been created, that instance will be the object returned to the client; otherwise a new instance is created, stored in a class member, and then returned to the client. The conditional statement is shown in Listing 6-27.

Listing 6-27. FaceBook class as a simple singleton

package
{
public class FaceBook extends FaceBookLogin
{
static protected var $_fbInstance : FaceBookLogin;

public function FaceBookA( target : IEventDispatcher = null )
{
super( target );
}

static public function getInstance() : FaceBookLogin
{
if ($_fbInstance)
{
$_fbInstance = new FaceBook();
}
return $_fbInstance;
}
}
}

The getInstance method is declared as a class member, creates a unique instance of the FaceBook class, and stores it as a class property. If an instance already exists when getInstance is called, the unique instance is returned to the client. This wrapper ensures the existence of only one instance.

With the creation of your singleton, you can use the instance as a global object. To obtain the reference, all you have to do is refer to the getInstance class method:

FaceBook.getInstance()
//returns the FaceBook object and stores it to return the same reference every time.

Once this object is created, you can insert the method into the appropriate classes (see Listing 6-28).

Listing 6-28. Class using FaceBook.getInstance

private var _faceBook : FaceBook;
//...cont

override public function intro() : void
{
_faceBook = FaceBook.getInstance();
trace( "_faceBook" , _faceBook );

var _userInfo : ProfileInformation = _faceBook.getUserProfile();
trace( "_userInfo" , _userInfo );

var obj : Object = _userInfo.fullProfile;

for (var key:String in obj)
{
trace( key + ' ' + obj );
}
if (!_faceBook.hasProfile)
{
_faceBook.addEventListener( FacebookEvent.COMPLETE , updateTextFields );
}
else
{
// ... text fields update implementation not shown.
}
// ... truncated code
}

As shown in Listing 6-28, a class can acquire the FaceBook object and then access the user’s profile information. Otherwise, it can attach an event listener for the moment a user logs in to Facebook.

When you add this to other classes that contain code similar to that in Listing 6-28, the same FaceBook object is always returned. This is due to the conditional statement in Listing 6-27.

Now, suppose your project manager informs you that you need to modify the application. The FaceBook feature, which was never intended to be a primary aspect of the application, has become so popular that the client wants to include the user’s profile image, as well as pluck random updates from their feeds. This doesn’t require much work, because FaceBookFacade already includes this behavior. You just need to add another few lines of code to hook into it.

Adhering to the open-closed principle, you create a new subclass of FaceBook called FaceBookExtendedProfile. FaceBookExtendedProfile gets the user’s avatar and status, and adds them to the current ProfileInformation (see Listing 6-29).

Listing 6-29. FaceBookExtendedProfile obtains the user’s status and avatar and appends them to shortProfile

package
{
public class FaceBookExtendedProfile extends FaceBook
{
public function FaceBookExtendedProfile()
{
}

protected override function userInfoLoaded( event : FacebookEvent ) : void
{
super.userInfoLoaded( event );
var profile : ProfileInformation = _faceBook.getUserProfile();
acquireAvatar( profile.userAvatarURL );
acquireStatus( profile.status );
}

protected function acquireStatus( xml : XML ) : void
{
shortProfile.statusXMLlist = xml..user_status;
}

protected function acquireAvatar( AvatarURL : String ) : void
{
if (AvatarURL.length < 1)
{
var bitmapData : BitmapData = new BitmapData( 100 , 100 , true , 0 );
shortProfile.avatar = bitmapData.clone();
return;
}

var loader : Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE,onAvatarAcquired );

var urlRequest : URLRequest = new URLRequest( AvatarURL );
var ldrContext : LoaderContext = new LoaderContext();
ldrContext.checkPolicyFile = true;
loader.load( urlRequest , ldrContext );
}

private function onAvatarAcquired( event : Event ) : void
{
var ldrInfo : LoaderInfo = event.target as LoaderInfo;
ldrInfo.removeEventListener( Event.COMPLETE , onAvatarAcquired );
var ldrContent : Bitmap = ldrInfo.content as Bitmap;
_bitmapData = ldrContent.bitmapData;
_shortProfile.avatar = _bitmapData;
}
}
}

The subclass FaceBookExtendedProfile now extends FaceBook. With the updates implemented, you only need to replace the static variable $_fbInstance with an instance of FaceBookExtendedProfile.

Because FaceBookExtendedProfile extends FaceBook, it has the appropriate privileges to modify the $_fbInstance reference. You add $_fbInstance=this; to the constructor to swap $_fbInstance with an instance of your new subclass (see Listing 6-30).

Listing 6-30. Revised FaceBookExtendedProfile

package
{
public class FaceBookExtendedProfile extends FaceBook
{
public function FaceBookExtendedProfile()
{
super();
$_fbInstance = this;
}
//... cont
}
}

With the extension complete, you need to consider how to use it. Because you’re attempting to modify the pointer of the $_fbInstance, you must instantiate FaceBookExtendedProfile before any calls are made to FaceBook.getInstance(). Otherwise, the incorrect reference will be returned to the client. The next dilemma is the confusion of an unsuspecting developer who attempts to modify the FaceBook class without realizing that the class is being overridden by FaceBookExtendedProfile.

This places you in a predicament with no good options. OOP is about reuse and cohesion, but all you’re left with are Band-Aid fixes. Given the circumstances, the only thing to do is to copy and paste the new behaviors of FaceBookExtendedProfile into the old FaceBook class, breaking the open-closed principle.

The issue with a simple singleton, as you’ve seen, is its inability to be subclassed. This is due to referencing a variable with a concrete Class object. Although use of static members is inflexible, they can be used in making a reference globally accessible. As this benefit of accessibility is seen as a tremendous asset, developers use static references all the time in many areas of code. However, these references make code inflexible when changes are introduced. This is why Simple Singleton isn’t the Singleton design pattern.

The Singleton Pattern

The Singleton pattern provides a global means to access a unique object while ensuring the extensibility of that object. Figure 6-8 shows the class diagram.

image

Figure 6-8. Singleton pattern class diagram

This pattern has the following parts:

· Concrete singleton

· Singleton interface

· Abstract Factory Method pattern

· Abstract product

· Concrete product

· Abstract creator

· Concrete creator

· Client

The pattern’s benefits are as follows:

· Grants global access to an object

· Maintains access to its unique instance

· Reduces the need for multiple global variables

· Permits subclasses

It also has this drawback:

· Requires configuration

A Comprehensive Look

The singleton is an object that enables access to a specific location in memory that preserves the integrity of an OO system. Rather than stitch a series of variables throughout an application, the Singleton pattern provides an ingenious to create and retrieve an instance.

The Singleton design pattern ensures that a particular object can have exactly one instance and one instance only, unless specified otherwise. To ensure the single instance, the sole means of instantiating an object is through the pattern. This prevents the instance from being modified anywhere else in the code. The added benefit is that the singleton becomes the exclusive access point from which the object can be acquired for use.

Using the Singleton pattern also provides flexibility through the use of inheritance. Although each object that uses the Singleton is required to remain a unique instance, the ability to be subclassed can’t be denied. This would be counterproductive given the open-closed design principle.

Vignette

The proprietor of the world’s best fried chicken, whom you met in the last example, continues to search for a way to bring his chicken to everyone in the world. The answer comes to him after he wakes from a terrible dream in which he couldn’t enhance his product without having to enter into new contracts. This was because he ensured that his products would never change, but he wasn’t the enforcer between his product and the clients.

With this realization, the chef decides to take charge of ensuring that he is the contract’s access point for those who want to taste his chicken. This way, he can improve his recipe and ensure that the changes are made without adding confusion among consumers. His name will become synonymous with slogan “The ONLY world’s best chicken”, and he’ll make sure of that.

The AS3 Cast

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

· Abstract creator: Defines the type that is used in its particular factory.

· Concrete creator: A factory subclass that contains the logic necessary to instantiate the appropriate object in a genus of products expected by the superclass.

· Abstract product: Exposes the interface that all concrete products of the given genus inherit.

· Concrete product: Extends the abstract product to express itself as a member of the type to be used in the logic of the creator.

· Singleton interface: Exposes the contract by which the client can obtain the unique instance. The interface possesses a unique method that acts as a wrapper around a class member instance.

· Concrete singleton: Implements the behaviors and necessary factories to use.

· Class member Instance: A reference associated with the class and not the object. This reduces memory allocation given any number of instances of a given class. Although public, a class member can be accessed in a manner that doesn’t require an instance. You get such a class reference using the static modifier.

· Client: Any aspect of the application or system that has prior knowledge of the abstract product, as well as the fully qualified name of the singleton class and its static method.

When It’s Useful

The Singleton pattern is useful in these situations:

· When exactly one instance of an object in an application is required

· When you need global access to solve a workflow issue (analytics, managers, etc.)

Example

The Singleton pattern structures code so that while enforcing a unique instance of an object, it lets a subclass become that unique instance, without requiring modification of existing code. A secondary role of the Singleton pattern is to reduce the number of global variables in an application by consolidating namespaces. To achieve such flexibility among unique instances, the structure of the singleton relies on uniform creation via parameterization. You create varying products by using a unified process: the abstract factory.

Although FaceBookExtendedProfile and FaceBook from Listing 6-27 and Listing 6-29 have varying implementations, they don’t have different interfaces. Therefore, although these interfaces don’t exhibit change, they should be interchangeable in a singleton’s instance. You know that to achieve the singleton’s global access, you use a static method. And because class methods can only reference class members, you need to hold the reference as a static member. Any message to your static method must return the object referenced by the static member_instance. In order to ensure that _instance points to a reference, you need a conditional statement, which you saw earlier in the discussion of the Simple Singleton pattern. This gives you global access to an object of a unique instance, intended for use in the application.

Listing 6-31 shows the internal mechanism of the FaceBookSingleton instance, which currently lacks an interface and an object to instantiate. To maintain flexibility, you need to parameterize an object to be instantiated by the getInstance method, while maintaining anonymity for the object to create. At the same time, you expose a uniform return type.

Listing 6-31. Internals of the FaceBookSingleton object

package
{
public class FaceBookSingleton
{
static private var $_instance : _____;

static public function getInstance() : _____;
{
if ( !$_instance )
{
$_instance = new _____;
}
return $_instance;
}
}
}

You use an the abstract factory to create an interface to create the product. You know the factory must return a given product and that this product is a subclass of a FaceBook interface.

image

Figure 6-9. The Singleton making use of the Abstract Factory

Listing 6-32. FaceBook

package
{
[Event(name="Connect", type=" FaceBookEvent")]
[Event(name="Complete", type=" FaceBookEvent")]
public class FaceBook extends EventDispatcher
{
static public const COMPLETE : String = "complete";
static public const CONNECT : String = "connect";
protected var _faceBook : iFaceBook;
protected var _shortProfile : ShortProfileInformation;
protected var _hasProfile : Boolean;

public function Login( target : IEventDispatcher = null )
{
_shortProfile = new ShortProfileInformation();
_hasProfile = false;
}

public function init() : void
{
_ready = false;
_faceBook = new FaceBookFacade();
// a class that utilizes my FaceBookGraphAPI
_faceBook.addEventListener( FacebookEvent.CONNECT , faceBookConnectHandler );
}

public function get facebook() : IFaceBook
{
return _faceBook;
}

public function get hasProfile() : Boolean
{
return _hasProfile;
}

public function get shortProfile() : ShortProfileInformation
{
return shortProfile;
}

protected function faceBookConnectHandler( event : FacebookEvent ) : void
{
}
}
}

Using FaceBook as an abstract class allows you to declare your interface. Your past classes become subclasses of the new abstraction. By abstracting the two classes, you can extract commonalities and offer default implementations that occur between both concrete classes.

Listing 6-33. FaceBookProfile

package
{
public class FaceBookProfile extends FaceBook
{
public function FaceBookProfile()
{
super( null );
}

override protected function faceBookConnectHandler( event : FacebookEvent )
image: void
{
if (event.success)
{
FacebookCall( _faceBook.queryUserInformation() ).addEventListener(
image FacebookEvent.COMPLETE , userInfoLoaded );

dispatchEvent( new FacebookEvent( FacebookEvent.CONNECT ) );
}
}

protected function userInfoLoaded( event : FacebookEvent ) : void
{
var aFaceBookCall : FacebookCall = event.target as FacebookCall;
aFaceBookCall.removeEventListener( FacebookEvent.COMPLETE , userInfoLoaded );

dispatchEvent( new FacebookEvent( FacebookEvent.COMPLETE ) );
var profile : ProfileInformation = _faceBook.getUserProfile();
_shortProfile.usrIdentifier = profile.userName;
_shortProfile.faceBook = true;
_hasProfile = true
}
}
}

Listing 6-34. FaceBookExtendedProfile

package
{
public class FaceBookExtendedProfile extends Facebook
{
public function FaceBookExtendedProfile()
{
}

protected override function userInfoLoaded( event : FacebookEvent ) : void
{
super.userInfoLoaded( event );
var profile : ProfileInformation = _faceBook.getUserProfile();
acquireAvatar( profile.userAvatarURL );
acquireStatus( profile.status );
}

protected function acquireStatus( xml : XML ) : void
{
shortProfile.statusXMLlist = xml..user_status;
}

protected function acquireAvatar( AvatarURL : String ) : void
{
if (AvatarURL.length < 1)
{
var bitmapData : BitmapData = new BitmapData( 100 , 100 , true , 0 );
shortProfile.avatar = bitmapData.clone();
return;
}

var loader : Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE,onAvatarAcquired );

var urlRequest : URLRequest = new URLRequest( AvatarURL );
var ldrContext : LoaderContext = new LoaderContext();
ldrContext.checkPolicyFile = true;
loader.load( urlRequest , ldrContext );
}

private function onAvatarAcquired( event : Event ) : void
{
var ldrInfo : LoaderInfo = event.target as LoaderInfo;
ldrInfo.removeEventListener( Event.COMPLETE , onAvatarAcquired );
var ldrContent : Bitmap = ldrInfo.content as Bitmap;
_bitmapData = ldrContent.bitmapData;
_shortProfile.avatar = _bitmapData;
}
}
}

Now that you have your product, you just need to construct the creator and abstract creator that are passed in to the Singleton. This creates an abstraction among passed-in objects that can be used with the Singleton pattern.

All you’re concerned with for this application is the appropriate instantiation of your object, so the abstract creator only has a factory method that returns an instance of FaceBook (see Listing 6-35). And as you know, with factory methods you should use a method containing the prefixmake or create. This example uses a method called makeUniqueFB (see Listing 6-36 and Listing 6-37).

Listing 6-35. AFaceBookCreator

package
{
public class AFaceBookCreator
{
public function makeUniqueFB() : FaceBook
{
}
}
}

Listing 6-36. FaceBookShortProfileFactory subclasses AFaceBookCreator and retains the knowledge of the concrete class to instantiate, FaceBook

package
{
public class FaceBookShortProfileFactory extends AFaceBookCreator
{
public override function makeUniqueFB() : FaceBook
{
return new FaceBook();
}
}
}

Listing 6-37. FaceBookExtendedProfile subclasses AFaceBookCreator and retains the knowledge of the concrete class to instantiate, FaceBook

package
{
public class FaceBookExtendedProfile extends AFaceBookCreator
{
override public function makeUniqueFB() : FaceBook
{
return new FaceBookExtendedProfile();
}
}
}

Finally, you need to enable the factory to be parameterized into a singleton to create the appropriate single instance (see Listing 6-38).

Listing 6-38. FaceBookSinglet on accepts an abstract factory that contains the appropriate product

package
{
public class FaceBookSingleton
{
static private var $_factory : AFaceBookCreator;
static private var $_instance : FaceBook;

static public function getInstance() : FaceBook
{
if ( !$_instance )
{
$_instance = $_factory.makeUniqueFB();
}
return $_instance;
}

static public function setFactory( FBFactory : AFaceBookCreator ) : void
{
$_factory = FBFactory;
}
}
}

The bolded code in Listing 6-38 adds the behavior required by the Singleton pattern to provide the flexibility required by an OO application. The appropriate factory is supplied to the singleton before the getInstance method. After the factory is passed in, the existing code can remain unchanged and continue to bind itself to the interface of the returned product.

FAQ

· Why is this approach better than using the Simple Singleton pattern?

The immediate answer is the flexibility it offers. In many languages, a static class can’t be overridden, preventing the use of polymorphism. The Simple Singleton pattern ensures that only one object instance is unique, as well as the access point to this object, by inserting this behavior into the object. Doing so gives a class behaviors that let it behave as a wrapper to itself.

By providing its own wrapper to secure itself, the product reduces loose coupling by the client. This reduces any reusable code to the remnants of objects used for a specific project.

· Why do other books show the Simple Singleton pattern as the Singleton design pattern?

The answer is a bit complicated. As I stressed in Chapter 4, design patterns use UML to avoid referring to any specific language. This is because every language is different. Some OO languages use abstractions, whereas others use interfaces; and some allow methods to bevirtual while others must be static.

The language that interprets each pattern plays a large role in how the pattern appears. The most important thing is understanding the problem the pattern solves and not using the model as the only source.

· What makes this approach so flexible?

In short, the pattern’s indirection makes it so flexible. Although this pattern allows unique instances to remain accessible, extendable, and global, it requires a lot of complexity. This indirection can be both good and bad.

· Can more than one object be accessed from the singleton?

Yes, as long as it fits the needs of your application and doesn’t overly complicate the code. The Singleton pattern aims to reduce the number of global variables in an application by allowing them to be acquired from a single access point.

Related Patterns

The following patterns are related to the Singleton pattern:

· Abstract Factory

· Builder

Summary

It’s very easy to overlook the chance to use a creational pattern and fall back on the new keyword. This is a “Get it done” mentality; and although I can sympathize with it as a developer, it doesn’t save you any time on the next project. The quick implementations may be the last nail in the coffin.

This doesn’t mean you should afraid of the keyword new, but consider how important it is for the declaration to be in the body where it resides. This is the deciding factor when you’re considering whether your code should use a creational pattern.

Abstraction is crucial. Specifics are always necessary in an application, but their placement is critical. The design patterns discussed in this chapter rely heavily on abstraction that makes code easier to change.

Key Points

· The new keyword may decrease the flexibility of your code as well as prevent internal reuse.

· The Factory Method pattern relies on inheritance to localize preparation and creational logic.

· The Abstract Factory pattern bundles families of related or dependent objects.

· The Singleton pattern allows for extension.

· The Builder pattern varies the internal representation of its product.

· A singleton should remain extensible.

· A pattern can become the client of other patterns.

· Simple Factory isn’t the Factory Method pattern or the Singleton pattern—it’s not even a pattern.