References:
Prog ActionScript 3.0 – Enumerations with Classes:
http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=04_OO_Programming_161_07.html
http://www.herrodius.com/blog/87
http://www.barneyb.com/barneyblog/2007/11/02/enums-and-actionscripts-static-initializers/
Environment:
ActionScript 3.0; Flex Builder 3.0 with Flex SDK 3.2
Keywords:
ActionScript 3.0, Enumerations with Classes, private constructor, singleton, static code block
Enumerations:
ActionScript 3.0 documents suggest the use of classes with only static constants as a way to create enumerations.
The first approach uses variables of basic types such as String, int, or uint within a class. In fact, Flash API use this approach, as in the following code, we are told:
public final class PrintJobOrientation
{
public static const LANDSCAPE:String = "landscape";
public static const PORTRAIT:String = "portrait";
}
The second approach involves a separate class with static properties for the enumeration: Here, each static property is an instance of the class and thus allows improved type checking. The example provided is as follows:
public final class Day
{
public static const MONDAY:Day = new Day();
public static const TUESDAY:Day = new Day();
public static const WEDNESDAY:Day = new Day();
public static const THURSDAY:Day = new Day();
public static const FRIDAY:Day = new Day();
public static const SATURDAY:Day = new Day();
public static const SUNDAY:Day = new Day();
}
An example usage is as follows:
function getDay():Day
{
var date:Date = new Date();
var retDay:Day;
switch (date.day)
{
case 0:
retDay = Day.MONDAY;
break;
case 1:
retDay = Day.TUESDAY;
break;
case 2:
retDay = Day.WEDNESDAY;
break;
case 3:
retDay = Day.THURSDAY;
break;
case 4:
retDay = Day.FRIDAY;
break;
case 5:
retDay = Day.SATURDAY;
break;
case 6:
retDay = Day.SUNDAY;
break;
}
return retDay;
}
Note that the return type is Day; this is how enhanced type checking comes into play.
Exercise for the Reader: Enhancing the Day Class Sample
Adobe documentation suggests an exercise for the reader: enhance this class by associating an integer with each day, as well as a string representation. Here is my solution:
package
{
public class MyDay
{
private var _dayNum:int;
private var _dayStr:Array = ["Sun","Mon","Tues","Wednes","Thus","Fri","Satur"];
public static const SUNDAY:MyDay = new MyDay(0);
public static const MONDAY:MyDay = new MyDay(1);
public static const TUESDAY:MyDay = new MyDay(2);
public static const WEDNESDAY:MyDay = new MyDay(3);
public static const THURSDAY:MyDay = new MyDay(4);
public static const FRIDAY:MyDay = new MyDay(5);
public static const SATURDAY:MyDay = new MyDay(6);
public function MyDay(dayNum:int)
{
_dayNum=dayNum;
}
public function get dayNum():int
{
return _dayNum;
}
public function get dayStr():String
{
return _dayStr[_dayNum]+”day”;;
}
public function toString():String
{
return dayStr;
}
}
}
class SingletonEnforcer {}
I had intended to use class SingletonEnforcer to restrict the use of MyDay constructor to this package, since I cannot make the MyDay constructor private; but that leads to TypeError 1115. According to http://www.herrodius.com/blog/87 , it is impossible to call the constructor of the inner class (i.e. SingletonEnforcer) in a static member of the top class.
The alternative is to use an unnamed static code block:
private static var _enumsInited:Boolean = false;
//unnamed static code block
{
_ enumsInited = true;
}
and then modify the constructor; the final code is as follows:
package
{
public class MyDay
{
private var _dayNum:int;
private var _dayStr:Array = ["Sun","Mon","Tues","Wednes","Thus","Fri","Satur"];
public static const SUNDAY:MyDay = new MyDay(0);
public static const MONDAY:MyDay = new MyDay(1);
public static const TUESDAY:MyDay = new MyDay(2);
public static const WEDNESDAY:MyDay = new MyDay(3);
public static const THURSDAY:MyDay = new MyDay(4);
public static const FRIDAY:MyDay = new MyDay(5);
public static const SATURDAY:MyDay = new MyDay(6);
private static var _enumsInited:Boolean = false;
//unnamed static code block
{
_enumsInited = true;
}
public function MyDay(dayNum:int)
{
if (_enumsInited)
throw new Error("[MyDay] The enum is already inited.");
_dayNum=dayNum;
}
public function get dayNum():int
{
return _dayNum;
}
public function get dayStr():String
{
return _dayStr[_dayNum]+”day”;
}
public function toString():String
{
return dayStr;
}
}
}
This works, because the static code is executed after all static members have been set!
From
http://www.barneyb.com/barneyblog/2007/11/02/enums-and-actionscripts-static-initializers/
In a nutshell, a static initializer is kind of like a constructor, but it’s for the class object itself, not instances of the class. It gets invoked during classloading, after all static properties have been set, but the class is turned loose for general consumption.
Here is the code where I exercised the above classes Day and MyDay:
package {
import flash.display.Sprite;
public class EnumClassAS3 extends Sprite
{
public function EnumClassAS3()
{
var dayOfWeek:Day = getDay();
trace (dayOfWeek);
//Today is (was) Saturday:
if (dayOfWeek == Day.SATURDAY) {
trace("[Day] SATURDAY");
}
else {
trace("[Day] Not SATURDAY");
}
var strDay:String;
switch (dayOfWeek)
{
case Day.SATURDAY:
strDay="Saturday"
break;
default:
strDay="Not Saturday";
break;
}
trace("[Day] strDay:" + strDay);
var myDay:MyDay = getMyDay();
trace("[MyDay] dayNum:"+ myDay.dayNum );
trace("[MyDay] toString:"+myDay);
trace("[MyDay] dayStr:"+ myDay.dayStr );
if (myDay == MyDay.SATURDAY) {
trace("MyDay is: " +"SATURDAY");
}
else {
trace("MyDay is NOT: " +"SATURDAY");
}
var myOtherDay=getMyDay();
if (myOtherDay == MyDay.SATURDAY)
trace("MyOtherDay is: " +"SATURDAY");
if (myOtherDay == myDay)
trace ("SameDay");
if (myOtherDay === myDay)
trace ("SameStrictDay");
var extraDay:MyDay=new MyDay(8);
}
private function getDay():Day
{
var date:Date = new Date();
var retDay:Day;
switch (date.day)
{
case 0:
retDay = Day.SUNDAY;
break;
case 1:
retDay = Day.MONDAY;
break;
case 2:
retDay = Day.TUESDAY;
break;
case 3:
retDay = Day.WEDNESDAY;
break;
case 4:
retDay = Day.THURSDAY;
break;
case 5:
retDay = Day.FRIDAY;
break;
case 6:
retDay = Day.SATURDAY;
break;
}
return retDay;
}
private function getMyDay():MyDay
{
var date:Date = new Date();
var retDay:MyDay;
switch (date.day)
{
case 0:
retDay = MyDay.SUNDAY;
break;
case 1:
retDay = MyDay.MONDAY;
break;
case 2:
retDay = MyDay.TUESDAY;
break;
case 3:
retDay = MyDay.WEDNESDAY;
break;
case 4:
retDay = MyDay.THURSDAY;
break;
case 5:
retDay = MyDay.FRIDAY;
break;
case 6:
retDay = MyDay.SATURDAY;
break;
}
return retDay;
}
}
}