No New is Good New: Using Inheritance, Composition, Delegation and anything else other than New in ActionScript 3.0 Design Patterns

bucketrule

Before examining why instantiating instances using new is not a good thing, let me explain where I got the idea. It came from the GoF (indirectly) and the Freemans’ Head First Design Patterns (directly). This is not to say that both acquaintance and aggregation type relationships cannot hold a reference to another class by instantiating an instance of the other class. (The Proxy example on this blog does that.) Likewise, it may be impossible to do serious development without using at least some new statements and so the title indeed contains a bit of hyperbole.

The key idea behind design patterns is that you want your programs to be as flexible as possible. The dictum, program to an interface, not an implementation is an invitation to more flexible designs. When you create an instance using new in effect you lock into using the specific implementation. The more new statements in a program, the more tied up it is in whatever implementation you’ve elected to instantiate.

At the same time, I wanted to go over the different class relationships to connect the conceptual with the actual. When I look at a class diagram and see different relationships between classes, often I feel queasy about the relationships independent of a specific example. This is especially true with non-ActionScript 3.0 examples where the application invokes some built-in feature of the alien language. Suddenly, the example is sucked into a black hole remaining a mystery for ActionScript developers. We’ll avoid that here.

Inheritance Is-A First Step

We are advised by the Gang of Four to favor composition over inheritance, but inheritance is a fundamental part of most design patterns, so it’s a good place to start. It’s also the easiest place to show where you can invoke a method without using new, We’ll begin with the symbol in the class diagram in Figure 1.

Figure 1: Inheritance relationship

As you can see in Figure 1, the relationship between the Parent class and Child class is pretty simple and straightforward. The Child inherits all of the Parent characteristics. As a result, the Child has a strong and tight relationship with the Parent with little flexibility. Now let’s implement that without using the new statement in a program that invokes the Child.

?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
//Parent Class
package
{
	import flash.display.Sprite;
 
	public class Parent extends Sprite
	{
		public function Parent()
		{
			 //constructor
		}
 
		public function parentMethod():void
		{
			trace("Is-a is using me, the Parent");
		}
	}
}
 
//Child Class
package
{
	public class Child extends Parent
	{
		public function Child()
		{
			this.parentMethod();
			childsPlay();
		}
 
		private function childsPlay():void
		{
			trace("This is a child original.");
			trace("Mouse location: "+ mouseX);
		}
	}
}

When you test this application (calling the Child) in either Flash or Flex, you’ll get the following output:

Is-a is using me, the Parent
This is a child original.
Mouse location: 147

I might add that the Parent class inherits the built-in Sprite class, and so the Child class inherits all of the Sprite class properties as well. To illustrate this, the mouseX property is inherited from the Sprite class. In turn, Sprite inherits mouseX from the DisplayObject class. So the Child class method is able to use the mouseX just as it would with any other class that inherits from a class that extends the Sprite class.

You may be thinking that inheritance is used in virtually every design pattern in our book and on this blog (not to mention the GoF book), and so what’s wrong with inheritance? Besides, inheritance is an essential part of OOP. In looking at the design patterns, the little triangle indicating inheritance is typically done so with an abstract class or interface. Where you see the key words extends or implements in a program, you will see the inheritance triangle. However, what you may not see is the fact that the parent class is either an interface or abstract class. Only the fact that the class name is italicized lets the developer know that the parent class is abstract, and a quick glance often misses that essential point. Inheritance from an abstract class or interface provides a looser coupling in that the subclass has a good deal of flexibility (think polymorphism) as to what the implementation will actually look like.

The further one moves down the structure from the origin class or classes to concrete subclasses, the more tightly bound subclasses become to the parent class. However, as you can see simply by looking at the ActionScript 3.0 reference documentation, which nicely maps the structure of the classes, a lot of inheritance is used to make up ActionScript 3.0. For example, the ActionScript 3.0 TextField class has a fairly long inheritance trail:

TextField -> InteractiveObject -> DisplayObject -> EventDispatcher -> Object

Subclasses from the TextField class would further tighten up the connections and possible inherited baggage. So while inheritance is fundamental to good OOP, where possible, GoF recommends other class relationships.

Acquaintance

When two classes are connected through acquaintance one class has a relationship to another class in the form of a pointer, reference or, less commonly, an instance. A solid black line with an arrowhead and optional reference name in a class diagram indicate that the class on the back of the arrow, uses the class it points to. Figure 2 shows a uses-a relation diagram:

Figure 2: Acquaintance

A recent example in this blog of an acquaintance can be found in the Proxy design pattern. The Proxy class holds a reference to the Real Subject. In the example the ProxyLogin class holds a reference to a RealLogin class as seen in this following code snippet:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
public function login():void
{
     if (loggedIn==null)
     {
          loggedIn=new RealLogin(username);
     }
     loggedIn.login();
}

That certainly keeps a reference to RealLogin(), but it’s not the best example of keeping a reference to another class. It instantiates an object of the class inside a conditional statement, and that’s a fairly weak kind of delegation. It instantiates an object when needed, and in that sense uses the other class. However, both the RealLogin and ProxyLogin implement theISecurity interface; so they already have a connection. Acquaintances are supposed to be loose, but they’re also supposed to associate one class with another—not just instantiate an instance of the class. Let’s look at a better example of acquaintance in the Observer pattern.

The relationship between the Subject interface and the Observer interface is a very nice example of class acquaintance. (See Chapter 8 ActionScript 3.0 Design Patterns for the full discussion of the Observer pattern.) The Subject interface has an acquaintance with the Observer interface. It does so in the parameter of the Subject’s methods:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
public interface Subject
{
	function subscribeObserver(o:Observer):void;
	function unsubscribeObserver(o:Observer):void;
	function notifyObserver(o:Observer):void;
}

That’s pretty simple, but it better shows a nice loose kind of relationship. On the Observer side, the interface is,

?View Code ACTIONSCRIPT
1
2
3
4
public interface Observer
{
      function update();
}

That really doesn’t tell you a lot, but it provides an idea of what might be considered an acquaintance. Essentially, holding a reference of some sort sets up a loose coupling. However, we need to look at aggregation to better understand acquaintance.

Delegation through Aggregation

I’m attracted to aggregation like a fly to a spider web—often meeting a similar fate as the fly. I’m easily entangled. Let’s start with the formal outline of aggregation. Again, you will see an arrow pointing to the aggregatee, but on the aggregator’s end is a diamond.

Figure 3: Aggregation

If you look carefully at Figures 2 and 3, they’re difficult to tell apart. Both types of relationships hold references to other classes. Usually, the two are differentiated by pointing out that aggregation is a stronger relationship than acquaintance and that the lives of the classes are intertwined in aggregation more so than with acquaintance. That’s true, but Gamma, et al note that differentiating one from the other is more a matter of intent than design. Both acquaintances and aggregations are typically included as pointers and references but less commonly they can be included as instances (as we saw with the Proxy example.) However, both relations are types of composition that go into creating a design pattern, and they do so using composition rather than inheritance.

The aggregation relationship is where the aggregator (Class A in Figure 3) has-a aggregatee (Class B in Figure 3). By my count 10 of the 23 design patterns use aggregation and 12 use acquaintance. (3 use both). Almost all of the design patterns use inheritance, but most inheritance is from an interface or abstract class.

Hang Loose

So loose coupling between classes is the key to all relationships and instead of worrying about aggregation, acquaintance and inheritance (and splitting hairs over their differences), the focus should be on loose coupling. The Template Method is one of the few design patterns that has neither acquaintance nor aggregation. However, it is wonderfully loose because its key algorithm is abstract but ordered. The operations that make up the key algorithm can provide details or be wholly abstract, leaving the details up to the concrete subclasses.

All of this discussion is the result of favoring composition over inheritance and keeping the use of the new statement to a minimum. To repeat, this does not mean that new cannot be employed either in an implementation (such as the State design pattern) or as a reference, as we noted in the Proxy. However, it was impossible to pass up a title like, No New is Good New so, while some of this discussion did touch upon the point so forcefully made by the Freemans, the message is really,

Hang loose, Dude

4 Responses to “No New is Good New: Using Inheritance, Composition, Delegation and anything else other than New in ActionScript 3.0 Design Patterns”


Leave a Reply