Gentle Reader: Now that we’ve worked through all of the design patterns in ActionScript 3.0 from GoF (well, Builder is still in the works, but that’ll be available soon), now would be a good time start going through the principles underlying design patterns. This will be the first in that series.
The 1987 OOPSLA keynote address by Barbara Liskov contained what has become known as the Liskov Substitution Principle (LSP). Essentially, the principle holds that
If a Client is using a reference to a base class it should be able to substitute a derived class for it without affecting the program’s operation
(Actually Dr. Liskov said something more like:
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
but I’m not about to…)
If the Client has an object of a certain type, it should be able to substitute a derived object of the same type. For example, suppose you have an abstract class named Automobile and from that class you have subclasses of Ford, Toyota, and Peugeot. Your Client has an object, myAuto:Automobile. The myAuto object can be any of the subclasses, and if a substitution is made for any one of them everything keeps on working without a problem and the change is unknown to the Client. So if you substitute a Ford for a Toyota, the Client can work with the objects without having to adjust for the change. What’s more, if you want to add a Fiat class as a subclass of Automobile, the myAuto object handles it with nary a whimper.
The one caveat is that the subclasses must all honor the contractual conditions of the parent class. So, any methods in the parent class must be functioning in the subclass (aka, derived class.)
Now you may be thinking, So what? If you’re at all familiar with other principles of OOP and Design Patterns, this principle may sound vaguely familiar, but what is the importance of this concept/principle/idea? It is this: Because the Client is unaware of the concrete class that the object may implement, the structure is far more resilient. Not only can the same structure be reused, it can be changed, updated and generally fiddled with without easily breaking anything. (Think of adding more car manufacturers to the Automobile class.) As far as the Client is concerned, as long as the interface rules are followed with the object, everything is hunky-dory.
A Simple Practice
As a principle, the Liskov Substitution Principle is easy to carry around in your pocket. If you write the following line in your Client (or even your Factory) you’re doing something wrong:
myObj:SubClassA = new SubClassA();
You know that another subclass of the same base class cannot be substituted for SubClassA. If you attempt to substitute SubClassB for myObj, it will fail. Now, instead, all you have to remember is to write,
myObj:ParentClass = new SubClass();
That’s (just about) it! Well, one more thing. The parent class needs to be an abstract class or an interface. Now, that’s it! How difficult is that to remember?
LSP in the Weird World
In looking at examples of the LSP principle, the two that pop up the most are the rectangle/square and ellipse/circle conundrums. We’ll use the rectangle/square example and try to provide two different alternatives to illustrate programming with LSP and without LSP.
Beginning with the geometric observation, all squares are also rectangles, we’re likely to create a structure like that shown in Figure 1:

Figure 1: Square is a child of Rectangle
After all, we can envision a square as nothing more than a rectangle with equal sides. So an operation such as,
makeRectangle(w,h);
is an effective way to make either a square or rectangle. We add the Square class simply to examine the LS Principle; otherwise creating rectangles or squares would be accomplished using the makeRectangle(w,h) method making sure that w and h are equal when making squares. The inheritance path clearly indicates that a Square object IS A Rectangle. (That is, the two have an IS A relationship.) However, because Rectangle is a concrete class if I substitute Rectangle for Square, I’m going to have to change the type. I cannot substitute an instance of Rectangle for an instance of Square. This violates the Liskov Substitution Principle.
Now, consider Figure 2. Instead of having Square as a child of Rectangle, both Square and Rectangle are children of the abstract class Boxes.

Figure 2: Abstract Class is Parent of both Squares and Rectangles
If I have an instance of Boxes, I can substitute either Square or Rectangle for the instance. In looking at an example, the Client is where we can expect to see the substitution principle at work. In the following example, the Client has a single object (subThis) typed as Boxes. However, that single object can gingerly create either a square or rectangle without the Client knowing the difference. It is designed to illustrate LSP.
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 | package { import flash.display.Sprite; import fl.controls.Button; import flash.events.MouseEvent; public class Client extends Sprite { private var subThis:Boxes; private var rec:Button=new Button(); private var squ:Button=new Button(); public function Client() { //Constructer adds buttons rec.x = 100,rec.y = 50; rec.width = 65; rec.addEventListener(MouseEvent.CLICK,doRec); rec.label = "Rectangle"; addChild(rec); squ.x = 170,squ.y = 50; squ.width = 65; squ.addEventListener(MouseEvent.CLICK,doSquare); squ.label = "Square"; addChild(squ); } private function doSquare(e:MouseEvent):void { if (subThis) { removeChild(subThis); } subThis=new Square(); subThis.createBox(70,0); subThis.x = 100,subThis.y = 100; addChild(subThis); } private function doRec(e:MouseEvent):void { if (subThis) { removeChild(subThis); } subThis=new Rect(); subThis.createBox(100,70); subThis.x = 100,subThis.y = 100; addChild(subThis); } } } |
The Client has two methods to create either a square or rectangle. However, both methods use the object subThis typed as Boxes. Using Boxes.createBox() (subThis.createBox()) the Client substitutes the Square and Rectangle for the Boxes object. Everything works smoothly. The way the program is set up when one is used, the box image changes from a square to a rectangle (or vice versa), but if you wanted, you could create as many as you want and splash them all over the stage. Figure 3 shows what you will see in the current setup.

Figure 3: Substituting Square and Rectangle Subclasses for Boxes Object
With this simple program, you should be able to see the ramifications for larger programs. In fact, the more your program grows, the more important LSP becomes. If you know that you can substitute any derived class for a base class, you are less likely to have unpleasant surprises. As a program grows and changes, you will have more modules, more objects, and more methods that need to interact in a program. The LSP helps keep those relations functional.
The Base Class
After working with the LS Principle, I wondered,
…is there any reason to create a concrete base class?
The answer is no.
Not a single design pattern has a structure with a concrete parent class.
What do I ever need a concrete parent class for? I can load up a parent class with functionality that can be used with subclasses, but I need some kind of wiggle room for the subclasses to extend the base class. Following the open/closed principle (“Open for extension. Closed for modification”), I can extend with added functionality from a superclass but I don’t want to modify it.
The following base class (Boxes) has a single method and imports the essential Sprite class needed for the graphics. The concrete classes override the function but they both inherit the Sprite class embedded in the base class.
1 2 3 4 5 6 7 8 9 10 11 12 13 | package { //abstract class import flash.display.Sprite; public class Boxes extends Sprite { public function createBox(w:Number,h:Number):void { //Abstract content } } } |
In an odd choice, ActionScript 3.0 has Graphic methods for a circle (drawCircle) and an ellipse (drawEllipse), but not for a square –only a rectangle (drawRect). In order to create an equivalent square and rectangle pair, I used the new Player 10 ActionScript 3.0 drawPath() method. (If you’re using Flash CS3 or versions of Flex prior to 3.2, alternative Square and Rectangle classes can be found at the end of this post.) In looking at the concrete classes, there’s not much difference other than the second parameter in the Square class is a dummy variable that is happy with number you stick there. The first parameter (h) is passed to a side variable (s) and only that single value determines the width and heights, which, of course, must be equal. First, you have the Rect class:
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 | package { public class Rect extends Boxes { private var recCmds:Vector.; private var recCoord:Vector.; public override function createBox(w:Number,h:Number):void { recCmds = new Vector.(5,true); recCmds[0] = 1; recCmds[1] = 2; recCmds[2] = 2; recCmds[3] = 2; recCmds[4] = 2; recCoord = new Vector.(10,true); recCoord[0] = 0;//x recCoord[1] = 0;//y recCoord[2] = w;//width recCoord[3] = 0; recCoord[4] = w;//width recCoord[5] = h;//height recCoord[6] = 0; recCoord[7] = h;//height recCoord[8] = 0; recCoord[9] = 0; graphics.beginFill(0x990000); graphics.drawPath(recCmds, recCoord); } } } |
Next, the Square class is similar, but notice the “dummy” label for the second parameter.
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 | package { public class Square extends Boxes { private var recCmds:Vector.; private var recCoord:Vector.; private var s:Number; public override function createBox(w:Number,dummy:Number):void { s = w; recCmds = new Vector.(5,true); recCmds[0] = 1; recCmds[1] = 2; recCmds[2] = 2; recCmds[3] = 2; recCmds[4] = 2; recCoord = new Vector.(10,true); recCoord[0] = 0;//x recCoord[1] = 0;//y recCoord[2] = s;//width recCoord[3] = 0; recCoord[4] = s;//width recCoord[5] = s;//height recCoord[6] = 0; recCoord[7] = s;//height recCoord[8] = 0; recCoord[9] = 0; graphics.beginFill(0x009900); graphics.drawPath(recCmds, recCoord); } } } |
As you can see, no rocket science is involved in either the drawing classes and their base class or the Client class. A single method is used to generate either, and the only real difference between the child classes is the enforcement of the equal width and height in the Square class.
LSP Lunch Bucket Rule
What can we take to work with the Liskov Substitution Principle? It’s nice to know and understand why the principle is in place, but who needs to have all of the implied tentacles of the principle rattling around in your head—especially considering the way Liskov stated it. We know the principle as you should be able to substitute any derived class from a base class where an instance of the base class exists. After further examination, the only way to do that is to use an abstract class or interface for all of your inheritance and implementations. Put more succinctly, the Lunch Bucket Rule is,
Only subclass from abstract classes. Do not inherit from concrete classes.
That’s easy enough to remember. Put that in your head and see if it helps move an OOP and Design Pattern agenda along at work.
\- – - – - – - – - – - — – - – - – - – - – - — – - – - – - – - – - — – - – - \
Flex client and Rect and Square Classes for Flash CS3 and Flex prior to 3.2
First, if you’re using Flex, you might want to use the following mxml program for your client (Ignore the Client.as class if you do):
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> <![CDATA[ import flash.display.Sprite; private var subThis:Boxes; private function doSquare():void { if ( subThis && rawChildren.contains(subThis) ) rawChildren.removeChild(subThis); subThis=new Square(); subThis.createBox(70,0); subThis.x = 100,subThis.y = 100; rawChildren.addChild(subThis); } private function doRec():void { if ( subThis && rawChildren.contains(subThis) ) rawChildren.removeChild(subThis); subThis=new Rect(); subThis.createBox(100,70); subThis.x = 100,subThis.y = 100; rawChildren.addChild(subThis); } ]]> </mx:Script> <mx:Button x="100" y="76" label="Square" click="doSquare()" id="squ"/> <mx:Button x="200" y="76" label="Rectangle" id="rec" click="doRec()"/> </mx:Application> |
Here’s the Rect class:
1 2 3 4 5 6 7 8 9 10 11 | package { public class Rect extends Boxes { public override function createBox(w:Number,h:Number):void { graphics.beginFill (0x990000); graphics.drawRect (0,0,w,h); } } } |
And now the Square class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package { public class Square extends Boxes { private var s:Number; public override function createBox(w:Number,dummy:Number):void { s=w; graphics.beginFill (0x009900); graphics.drawRect (0,0,s,s); } } } |

The Design Pattern Principles for ActionScript 3.0: The Liskov Substitution Principle by William B. Sanders, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
Related posts:

Bill Sanders
I have to say this is the best blog ever. Keep up the good work. Do you speak at Flex 360? If not you should.
One question?: What is this saying/doing, never seen this before?
private var recCmds:Vector.;
&
recCmds = new Vector.(5, true);
What is the “new Vector.” and why this instead of “new Vector” and why “recCmds:Vector” instead of “recCmds:Vector”?
Thanks, J
Hi Jason,
It’s our blog software. It requires that we put in < for the less than symbol and > for the greater than symbol. This is what the declarations really look like.
private var recCmds:Vector.<int>
private var recCoord:Vector.<Number>
We have to work something out when using Vectors because if we put in the symbol substitutes, when readers cut and paste or download the listings, they’ll get the wrong symbols.
Glad to hear you like our blog. We lucked out and have a terrific reader base.
Kindest regards,
Bill
Hi Bill,
Thanks for the great post. While many of us apply these principles on a daily basis, it’s great to see them in writing. It refreshes the “why” behind the things we do, forcing us to consiously step back and think about them again. I’ll be looking forward to this new series of articles.
Tyler.
Hi Tyler,
That’s the same thing we were thinking. Most of the time it’s just as easy to program “right” as it is “wrong” and by looking into the whys of different programming principles, it’s easier to keep in mind why a principle was developed in the first place.
Take care,
Bill