Take a Design Pattern to Work Part II: A Little OOP

Gentle Readers: Before reading this post, you’re advised to look at Take a Design Pattern to Work Part I: Identifying the Problem. It provides the necessary context for this post. Also, keep in mind that this series of posts is walking through a process and some of the steps may seem way too simple. We’re trying to imagine communicating with others who may not be as technically adept as you, and each step is simplified.

Getting Off the Timeline

As the readers of this blog are well aware, the Timeline in Flash is a valuable tool for animation. By using the Timeline in conjunction with symbols, IK and tweening, all kinds of wonderful creations are possible. However, the Timeline is not a good place for code, and again, this is nothing new to readers of this blog. So why bring it up?

If you peruse the ActionScript job openings at places like Dice.com and Monster.com, you’ll find openings that include the following requirements:

The successful candidate should have at least three years experience using ActionScript 2.0 with knowledge of ActionScript 3.0 a plus. He/she should also have the ability to maintain and update legacy Flash sites with ActionScript 1.0. A knowledge of OO programming and design patterns is strongly desirable.

Work that includes maintaining a site written in ActionScript 1.0 (and even ActionScript 2.0 in some cases) almost certainly means that some or all of the code is written on the Timeline and possibly even embedded in the individual symbols —buttons and movie clips. In other words, a good deal of the work is playing Where’s Waldo? with the ActionScript scattered all over the place. For me, working to maintain such a site is somewhere south of Dante’s 9th Circle of Hell. (You remember Dante’s Divine Comedy from that humanities class you had to take.)

In Part I of this post series, the code is embedded in an ActionScript layer on the Timeline. Maintaining the site is pretty simple both in making changes and adding new materials. The developer makes changes by changing the image file and the text contents in any single keyframe. Additions are made by adding keyframes in the Options layer, code in the ActionScript layer and buttons in the Buttons layer. That’s not a difficult plan. So why change?

With a relatively small staff in the company, there’s probably no reason to change it at all. However, as the staff grows or they want to add more to the site, especially in terms of additional graphics and animated materials, the size of the SWF file grows as well. Pretty soon, you’re making pre-loaders, and that’s a good sign that you’re in trouble.

In addition to the problems in generating a big fat SWF file, a single set of ActionScript statements can only grow into a larger and less manageable set of code. For a small application, it works fine, but as applications grow, unless some of the inherent problems are addressed, an error prone application begins to emerge. Change becomes more problematic and the program begins to lose functionality as well as flexibility.

The Client and the Request

A good place to start is with the Client class. (I’m going to capitalize Client where I’m referring to the Client as a class. Non-cap client refers to all other uses of the term such as client-server or Our client wanted us to develop a flexible application.) The Client is the gimme class–“Gimme this! Gimme that!”—in non-idiomatic English, that would be “Give me this! Give me that!” It makes requests from the set of classes that make up the design pattern. Since we haven’t got a design pattern at this point, think of the Client as the class we need for making requests. Also, as a general concept, think of the Client as making requests from other classes. That is, instead of making requests from itself, while possible from a self-contained function, the Client has a reference to another class or interface.

Some design patterns provide the position of the Client in the class diagram and others do not. For example, on pages 66-67 of ActionScript 3.0 Design Patterns, you can see the Client class in the diagram in both the Simple Factory Method and the Factory Method design pattern, but on page 131, you see no Client class in the Decorator design pattern. That doesn’t mean you’re not going to use a Client class. It simply means your Client class will make its requests from the pattern but is not implied or part of the pattern itself. Patterns with implied Clients such as the Proxy pattern display the Client ghosted or faded. Otherwise, a visible Client in a class diagram means that the Client is part of the design pattern. About half the design patterns show the Client as part of the pattern or implied. An implied connection means that means the Client is expected to have a connection between itself and a specific class in the pattern but is not part of the pattern’s structure. Sometimes, a Client is displayed with relations to more than a single other class in the pattern. One example is the Interpreter pattern.

The Request for an Object

The Client makes a request from another class that has built the desired content. This may be an object or process. A simple example would be to request a graphic image that was created in an image class. In the example from Part I of Bring a Design Pattern to Work, the request is in the form of buttons serving as UIs. Each button requests a different Staff page. In essence the request is to go to and stop at a specified keyframe. So, let’s take the ActionScript off the Timeline and create a Client class and object classes for the three staff members. The Client requests one of three staff members; so all we need to do is to create three Staff classes. The Client can create its own request UIs using Button components (which in themselves are classes.)

We can imagine several different strategies to request the three classes with images and text. First, we could create three SWF files, each with a different staff member with image and text. That’s pretty easy in Flash and Flex. Just slap the graphic and text right on a black background that’s that. Figure 1 shows the setup for a Flex application. After saving and testing the application, you can use the automatically generated SWF file in Flash or Flex. Of course you’d have to create some kind of loader to place the SWF files where you want them, but it would work just fine.

figure1

Figure 1: Creating SWF file in Flex

Using your imagination, you can think of lots more ways that a Client could request an image with a text caption and how to set up the image and text that will be requested. If your customer wants to make changes on her own without having to know a thing about Flash or Flex, then the process for the developer becomes a little tougher. You’d need a way to load image and text files independently and place them on the stage. The customer could just change the contents of the images and text for staff changes. If more staff members are added, the developer would have to go in and add more requests (buttons) to the Client and somehow fix the Object class to accept more images and text captions. Figure 2 diagrams the Client making requests directly to each class.

figure2

Figure 2: Client making requests from each class

Each of the Staff classes can then load up the necessary image and text. Adding new staff is simple. Just copy and paste any of the classes and change the image and text targets for the class. The following pseudo-code shows what each staff class looks like:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//NOTE: This is pseudo-code. It does not work.
package
{
          import.Sprite;
          import.ClassesForLoaders;
          import.ClassesForText;
 
          public class StaffX extends Sprite
          {
                    public function StaffX()
                    {
                              //Text field and its properties
                              new TextField();
                    }
 
             //Method for loading image
             public function loadImage(from Client):void
             {
                         loader.load(from Client);
              }
 
              //Method for loading text
 	      public function loadText(from Client)
              {
                         urlLoader.load(from Client);
               }
          }
}

Inheritance

If you stop and think about this for a second, you realize that if all of the staff classes are pretty similar in their functionality, why not just create a parent class and instantiate the other classes as inheriting a parent class? As each new child class is added, all you’d need to do is to use a loading method inherited from the parent class. Then each Staff class could be just a pair of loading methods that load the requested materials. Figure 3 shows a diagram of this new arrangement:

figure3

Figure 3: Client making requests through parent class

After all, we know that inheritance is one of the cornerstones of OOP, and in looking at Figure 3. It sure looks like good OOP. That’s as good a place to start with introducing OOP concepts (inheritance) as anywhere.

Client Jobs

Because the focal chore of the Client class is to make requests, it may seem either trivial or marginal to give it more than a cursory glance. However, as you will see in this series of posts, it can be crucial. So let’s pay the Client its due.

The request UI in the first post of this series was the Button component, and we’ll continue using that UI. The requests change only slightly. Instead of the requesting the playhead to move to and stop at a particular keyframe, this time the Client requests a class representing one of three staff positions. So the buttons with their attending events and event-handlers are all part of the Client class.

In addition to making requests, the Client has some setup chores. It places a logo and a ‘splash’ page on the stage. Both are made up of movie clip objects in the Library. The logo stays on the stage, but as soon as the photos and text from the staff begin to appear, the splash page disappears. That’s it for the logo and splash page.

Keeping in mind that this application uses subclasses, the first practice to keep in mind is:

Program to an interface; not an implementation

At this point, the parent class (Staff) is a pretty static interface, but for the sake of good practices go for a looser typing when possible. The child classes, Designer, Developer, and HCI, are implementations; so we’ll treat the parent class as an interface.*

*Note: Both interfaces and abstract classes are considered interfaces. I am well aware that ActionScript 3.0 does not have abstract classes, but the concept of an interface here is not the ActionScript statement, interface, but instead it refers to the more general idea of a supertype. See pp. 45-49 of our book for more details. Also, the Freemans have a great explanation of the concept on page 12 of Head First Design Patterns.

Thus, in declaring the private variables for the different subclasses of the Staff class, they are typed as Staff. It’s a looser kind of typing even though at this stage of the game, it’s not a whole lot looser given the very static nature of the child classes emerging from the parent class Staff.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package
{
          import flash.display.Sprite;
          import fl.controls.Button;
          import flash.events.MouseEvent;
 
          //Client Class
          public class Client extends Sprite
          {
                    private var logo:Logo=new Logo();
                    private var splash:Splash=new Splash();
                    private var design:Staff;
                    private var develop:Staff;
                    private var hci:Staff;
                    private var lastClass:Staff;
                    private var desBtn:Button=new Button();
                    private var devBtn:Button=new Button();
                    private var hciBtn:Button=new Button();
                    private var staffNow:String;
 
                    public function Client()
                    {
                             //Add the buttons to provide a UI for the requests
                              desBtn.label = "Designer";
                              desBtn.addEventListener(MouseEvent.CLICK, selectStaff);
                              addChild(desBtn);
                              desBtn.x = 424,desBtn.y = 66;
 
                              devBtn.label = "Developer";
                              devBtn.addEventListener(MouseEvent.CLICK, selectStaff);
                              addChild(devBtn);
                              devBtn.x = 424,devBtn.y = 116;
 
                              hciBtn.label = "HCI";
                              hciBtn.addEventListener(MouseEvent.CLICK, selectStaff);
                              addChild(hciBtn);
                              hciBtn.x = 424,hciBtn.y = 166;
 
                             //Place the logo and splash page on the stage
                              logo.x = 16,logo.y = 16;
                              logo.width = 150,logo.height = 121.5;
                              addChild(logo);
 
                              splash.x = 32,splash.y = 168;
                              addChild(splash);
                    }
 
                    //Client request list
                    private function selectStaff(e:MouseEvent)
                    {
                              //Remove the initial text block (in a movie clip)
                              splash.visible=false;
 
                              //Remove previous image and text
                              if (lastClass)
                              {
                                        removeChild(lastClass);
                              }
 
                     //Change the button labels to lowercase
                      staffNow = e.target.label.toLowerCase();
 
                      //Use the switch statement to sort our the requests
                              switch (staffNow)
                              {
                                        case "developer" :
                                                  develop = new Developer();
                                                  addChild(develop);
                                                  lastClass = develop;
                                                  break;
                                        case "designer" :
                                                  design = new Designer();
                                                  addChild(design);
                                                  lastClass = design;
                                                  break;
                                        case "hci" :
                                                  hci = new HCI();
                                                  addChild(hci);
                                                  lastClass = hci;
                                                  break;
                              }
                    }
          }
}

Normally you would not name your Client class, “Client,” but instead you’d provide something more descriptive. However, because this is an exercise to clearly identify the different parts that make up a design pattern, it is helpful to do so here.

The Parent Class

Often in design patterns you’ll have more than a single parent class, but in this OOP pattern, all we’re using the single parent class for is to illustrate inheritance. This particular parent class is very handy because it creates a text field, loads external text in and then load in a graphic or SWF file. (What’s not to like!). Then, we’ll subclass all the child classes that will use it.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package
{
          import flash.display.Loader;
          import flash.net.URLRequest;
          import flash.net.URLLoader;
          import flash.display.Sprite;
          import flash.text.TextField;
          import flash.events.Event;
          import flash.text.TextFieldType;
          import flash.text.TextFormat;
 
          //Parent class
          public class Staff extends Sprite
          {
                    private var loader:Loader;
                    private var url:URLRequest;
                    private var fileNow:URLRequest;
                    private var txtLoader:URLLoader;
                    private var loadCheck:URLLoader;
                    private var textField:TextField = new TextField();
                    private  var textFormat:TextFormat = new TextFormat();
 
                    public function Staff()
                    {
                              //Set up text field and text format
                              textField.type = TextFieldType.DYNAMIC;
                              textField.wordWrap = true;
                              textField.textColor = 0x007700;
                              textFormat.font = "Arial Black";
                              textFormat.size = 16;
                              textField.defaultTextFormat = textFormat;
                    }
 
                    //Load the external text
                    protected function loadInfo(txtInfo:String):void
                    {
                              txtLoader = new URLLoader();
                              txtLoader.addEventListener(Event.COMPLETE,nowLoaded);
                              fileNow = new URLRequest(txtInfo);
                              txtLoader.load(fileNow);
                    }
 
                    //Place loaded text into text field
                    private function nowLoaded(e:Event):void
                    {
                              loadCheck = URLLoader(e.target);
                              textField.text = loadCheck.data;
                              textField.width=200;
                              addChild(textField);
                              textField.x = 180,textField.y = 331;
                    }
 
                    //Load the graphic image or SWF file
                    protected function loadImg(img:String):void
                    {
                              url = new URLRequest(img);
                              loader=new Loader();
                              loader.load(url);
                              addChild(loader);
                              loader.x = 150,loader.y=130;
                    }
          }
}

Note that most of the methods are protected, and one is private. As usual, the constructor is public. The protected methods are such so that they have some encapsulation and yet can be used by children of the parent class.

All the Little Kiddie Classes

Now that the Client and main parent class is ready, the target of the requests can be built. These have been stripped down to illustrate how simple it is to use inheritance to get what you need. At this point the site only needs three children classes, one each for the different departments:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//Designers
package
{
          public class Designer extends Staff
          {
                    public function Designer()
                    {
                              loadInfo("text/designer.txt");
                              loadImg("images/designer.png");
                    }
          }
}
 
//Developers
package
{
          public class Developer extends Staff
          {
                    public function Developer()
                    {
                              loadInfo("text/developer.txt");
                              loadImg("images/developer.png");
                    }
          }
}
 
//HCI Folks
package
{
          public class HCI extends Staff
          {
                    public function HCI()
                    {
                              loadInfo("text/hci.txt");
                              loadImg("images/hci.png");
                    }
          }
}

The only remaining chore is to place the text files and image files in the text and images folders. The original request from the Client class is simplified by using Button components and their labels to identify the desired staff. If you’d rather not have a big conditional switch statement, you can make each button have a different event handler. You can view the application here and download the application here.

When you test your application, you should see pretty much the same thing that you saw with the original application. None of the code is on the Timeline, and all the customer has to change is the content of the text and images in the folders to change what the viewer will see. Figure 4 shows what you can expect to see when you test the application.

figure4

Figure 4: Delivered request

If you review the first post of this series you’ll see similarities and differences. The buttons in Figre 4 pick up the background color, and the logo has a better gradient in the sun behind the Sandlight text.

More Help on the Way

At this point, you’ve seen the progression from legacy ActionScript stuck on a Timeline to using OOP. By thinking about loosening up an application, you’re beginning to think about a flexible program where change and update are easier. If you look at your programs at work in this way, you can begin to think of how they can be made stronger and more flexible at the same time. In the next installment, we’ll take the penultimate step on the way to a design pattern for this application.

  • Share/Save/Bookmark

9 Responses to “Take a Design Pattern to Work Part II: A Little OOP”


  1. 1 RyanL

    Thanks again for another informative post Bill. It is truly appreciated. One thing I found interesting was your mention of using protected methods and why you did so. Although I am still not clear on exactly why a protected method is the best choice here.

    Cheers,

    RyanL

  2. 2 Dale

    Thanks for the nice article.
    Its good to see an actual implementation that uses a ‘website’, even if its very simple. Makes it far easier to make connections between developing with design patterns and what most people seem to do, in Flash anyway, build websites.

  3. 3 TK

    Ryan,
    In AS3 the protected keyword is an access modifier for a field (method or instance variable) of a class which limits access to subclasses only. IE: You can only get access to a protected method of a class in a subclass of that class.

    For example:
    public class Whatever {

    public Whatever() {}

    protected function getValue():Object {…}
    }

    Only a class subclassing Whatever would be able to call the “getValue” method.

    Access modifiers vary on your language. In Java, protected is similar but also allows package-level access. In AS3, no package-level access is allowed, it must be a parent-child relationship.

    - TK

  4. 4 Bill Sanders

    Hi Ryan,

    Basically, creating a private variable or function is a good way to encapsulate the variable or function (method.) It’s just a good (and easy) habit for OOP. In the example, all of the child classes had to use the methods in the parent class, and by creating a protected method, the methods were encapsulated to the class and its descendants.

    I believe a good OOP habit is to use private or protected access where possible to help sustain encapsulation. TK’s comments were helpful as well.

    Kindest regards,
    Bill

  5. 5 Bill Sanders

    Hi Dale,

    A certain irony lies in the fact that the first sentence of the GoF book notes that design patterns are difficult. Getting them into the workplace is even more difficult, but that part isn’t discussed as much. (Note to self: Suggest to Gang of Four to explain how to accomplish the latter.)

    If anyone reading this blog can share a story of how design patterns came into a functioning part of their company, such comments would be most welcomed!

    Best wishes,
    Bill

  6. 6 anggie

    Nice articles as usual, Bill!

    I’d like to translate this series into my language when I have time.

    Personal story of mine, I used to work with “unstable” specs ( who doesn’t ? lol ) and patterns have been very helpful to anticipate unforeseen requirement changes, at least they can help minimize the impact. Strategy, FrontController and ModelLocator are those that I use most. And I’m glad that I bought your book ;-)

  7. 7 Bill Sanders

    Hi Anggie,

    What a great way to put it!

    …anticipate unforeseen requirement changes…

    In some way, most (if not all) design patterns help to deal with unanticipated requirement changes. And of course in the real world of Internet based programs, change is the only constant.

    Kindest regards,
    Bill

  8. 8 sangram

    Hi ,

    In the downloadable source files, Client.fla seems to having some problem because I couldnt open it in Flash CS3.
    Can you please make the correct client.fla available for download.

    Thanks in Advance .

    Regards,
    Sangram

  9. 9 William B. Sanders

    Hi Sangram,

    It’s set up for Flash CS4 and/or Flex Builder. All you have to do is to create a new CS3 Fla, and in the Document Class window in the Properties panel type in ‘Client’ (w/o the quotes) and that should do the trick.

    If it doesn’t, let me know.

    Kindest regards,
    Bill

Leave a Reply