Chapter 5. Factory and Template Method Patterns

<feature><title>In This Chapter</title> </feature>

When creating groups of related classes, it’s important to maintain those relationships during object creation. One way to do this is with the Factory Method design pattern. The Factory Method pattern is a creational pattern and solves the problem of creating objects without specifying a concrete type. This is most often used in abstract classes that define a method for object creation. Subclasses can then override this method to define the specific object to be created.

The Factory Method is most often used in conjunction with another pattern called the Template Method. To better understand the Factory Method and provide more context for this solution, we’ll also look at the Template Method in this chapter. Because the Factory Method uses and then builds on many of the same concepts, we’ll look at the Template Method first.

Abstract Classes

Abstract classes play a major role in the Factory and Template Method patterns. Although ActionScript 3.0 doesn’t natively support them, we can still use the concept of abstract classes and abstract methods. An abstract class is a class that is always extended and never instantiated directly. Its use is similar to that of an interface, but there is one major difference: An interface defines only the public method signatures, but an abstract class defines both the interface and the implementation.

An abstract class uses something called an abstract method, which has no functionality but serves only as a placeholder. In other languages such as C# and Java, you can define these abstract methods using the abstract keyword that tells subclasses they must override this method. Because ActionScript 3.0 does not have an abstract keyword, you might consider the convention of throwing an exception inside the abstract methods. Such an approach won’t throw an error during compilation, but it will during runtime. The bottom line is that there is no sure way to enforce abstract methods in ActionScript 3.0.

You must know about two specific keywords when you’re working with abstract classes in ActionScript 3.0. The first is the override keyword. Subclasses must use this keyword to override an abstract method defined in a base class. The method signature must also match exactly.

The other keyword is final. This term can be used by abstract classes that define methods its subclasses cannot override. We’ll use the final keyword when we define Template Method patterns.

Template Method

A Template Method is defined in an abstract class that sets a general algorithm made up (at least partially) of abstract methods. The steps of that algorithm are defined when subclasses override the abstract methods. The structure of the algorithm is maintained in the Template Method.

Consider the following example in which we have an abstract class that defines the way games are initialized:

package com.peachpit.aas3wdp.factoryexample {

   public class AbstractGame {

      // Template Method
      public final function initialize():void {
         createField();
         createTeam("red");
         createTeam("blue");
         startGame();
      }

      public function createField():void {
         throw new Error("Abstract Method!");
     }

      public function createTeam(name:String):void {
         throw new Error("Abstract Method!");
      }

      public function startGame():void {
         throw new Error("Abstract Method!");
      }
   }

}

The initialize() method in the preceding example is the Template Method. It defines how the game is initialized by first calling the createField() method, then creating the teams with the createTeam() method calls, and finally calling the startGame() method. However, the methods it calls are not functional in this class. It’s the responsibility of the subclass to define exactly how the field and teams are created and how the game is started.

Now we will create a FootballGame class that extends our AbstractGame class. This subclass overrides the abstract methods that are called from the initialize() Template Method in the abstract base class.

package com.peachpit.aas3wdp.factoryexample {

   public class FootballGame extends AbstractGame {

      public override function createField():void {
         trace("Create Football Field");
      }

      public override function createTeam(name:String):void {
         trace("Create Football Team Named " + name);
      }

      public override function startGame():void {
         trace("Start Football Game");
      }

   }

}

As you can see, our FootballGame class overrides the createField(), createTeam(), and startGame() methods to make them specific to football. However, the initialization algorithm is maintained. You can see how this same technique could also be used to build a BaseballGame or a BastketballGame class. We can run the example using the following client code:

package com.peachpit.aas3wdp.factoryexample {

   import com.peachpit.aas3wdp.factoryexample.FootballGame;
   import flash.display.Sprite;

   public class FactoryExample extends Sprite {

      public function FactoryExample() {
         // Create an instance of FootballGame
         var game:FootballGame = new FootballGame();
         // Call the template method defined in AbstractGame
         game.initialize();
      }

   }

}

The following shows the output from the preceding example. As you can see, the overridden methods in the subclass were called by the Template Method. The algorithm was maintained in the Template Method while the details were deferred to subclass methods.

Create Football Field
Create Football Team Named red
Create Football Team Named blue
Start Football Game

Factory Method

Without too much effort, we can now turn the preceding Template Method example into a Factory Method example. It’s very common to implement Factory Methods in a Template Method.

In the preceding Template Method example, our createField() method doesn’t return anything; it just traces out the phrase “Create Football Field.” Let’s update this so it creates and returns a field object. Because different games have different field types, we’ll create an interface called IField that all the field classes will implement. Our interface will define a single method called drawField():

package com.peachpit.aas3wdp.factory {

   public interface IField {

      function drawField():void;

}

}

Now we’ll build a FootballField class that implements the IField interface. To keep our example focused, we won’t actually draw a football field to the stage, but you can fill in the blanks. Here’s the basic FootballField class definition:

package com.peachpit.aas3wdp.factoryexample {

   import com.peachpit.aas3wdp.factoryexample.IField;

   public class FootballField implements IField {

      public function drawField():void {
         trace("Drawing the Football Field");
      }

   }

}

The purpose of the Factory Method is to link up two or more separate but related class hierarchies. The first hierarchy is the AbstractGame class and its subclasses: FootballGame, BaseballGame, and BastketballGame. Our second class hierarchy is now the IField interface and the classes that implement it: FootballField, BaseballField, and BasketballField. The AbstractGame and IField objects are related, but the specific creation of these objects is determined by the game subclasses. Figure 5.1 shows how our class hierarchies match up.

The hierarchy of classes in the Factory Method example.

Figure 5.1. The hierarchy of classes in the Factory Method example.

Now we can refactor the createField() and initialize() methods of our AbstractGame class to reflect the existence of an IField object. Our createField() method is now a Factory Method that returns an object that implements the IField interface. The initialize() method can now go one step further and call the drawField() method on the IField object, as shown here:

package com.peachpit.aas3wdp.factoryexample {

   import com.peachpit.aas3wdp.factoryexample.IField;

   public class AbstractGame {

      // Template Method
      public final function initialize():void {
         var field:IField = createField();
         field.drawField();
         createTeam("red");
         createTeam("blue");
         startGame();
      }

      // Factory Method
      public function createField():IField{
         throw new Error("Abstract Method!");
      }

      public function createTeam(name:String):void {
         throw new Error("Abstract Method!");
      }

      public function startGame():void {
         throw new Error("Abstract Method!");
      }
   }

}

This abstract class and template algorithm are still completely anonymous and the specific objects created are in the hands of the subclass. Let’s refactor the FootballGame class now to create and return a FootballField object:

package com.peachpit.aas3wdp.factory {

   import com.peachpit.aas3wdp.factory.FootballField;
   import com.peachpit.aas3wdp.factory.IField;

   public class FootballGame extends AbstractGame {

      public override function createField():IField {
         return new FootballField();
      }

      public override function createTeam(name:String):void {
         trace("Create Football Team Named " + name);
      }

      public override function startGame():void {
         trace("Start Football Game");
      }

   }

}

If we run this example, we’ll get the following output:

Drawing the Football Field
Create Football Team Named red
Create Football Team Named blue
Start Football Game

If you think this is a Factory Method, purge that bit of information from your head and keep reading because the Factory Method is much more. In fact, the preceding example isn’t even a design pattern at all. It’s commonly referred to as a Simple Factory or a Parameterized Factory Method. Not to say that it isn’t useful; in fact, we use this technique in Chapter 12, “State Pattern”, to set the state based on a name.

Summary

Abstract classes are a very important tool in object-oriented design. They are most commonly used in class libraries and frameworks because they are a solid way to factor out common behavior across subclasses.

The Template and Factory Method design patterns are handy when you’re working with abstract classes. The Template Method allows you to create a common algorithm defined generally whose specific steps will later get defined by concrete subclasses. And the Factory Method allows you to trigger the creation of objects in an abstract class, but to defer the specific type to the subclass.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.54.242