One thing that annoys me from time to time is the lack of support for enumerated types. For those without experience in different languages (like C++), an enumerated type (enums) is an easy to way specify a data type to a variable that has a set amount of possibilities.
For example, if you have a class named ‘DeskLamp’ that has a property ‘state’, that property could be a of a ‘LightState’ enum which only has 2 possible entries, ‘On’ or ‘Off’.
Get the idea? This has many advantages to developers because it limits the possible inputs to that property and saves time because typos are caught at the compiler and not during runtime, which can be hard to debug. Essentially, it restrains developers from making a mistake; this can save time when developing in a team environment.
Even though Actionscript does not have enums, there is a way to circumvent this. There are many solutions posted online, and I looked at all of them, but there were all slightly flawed. I made my own version that would truly limit the possibilities to the developer. The way we do this is by creating static constants within a class that are instances of that same class, then have a conditional within the constructor that is rendered false after the static initializer is completed. Sounds complicated huh?
This example should clear a few things up. I just created an enum class for user roles ‘ADMIN’, ‘USER’ and ‘GUEST’.
package com.codemonkeycreative.enums
{
public final class UserRole
{
// The possible enums for this class
static public const ADMIN:UserRole = new UserRole('Admin', 0);
static public const USER:UserRole = new UserRole('User', 1);
static public const GUEST:UserRole = new UserRole('Guest', 2);
// A list of all the enums for easy referencing if needed
static public const roles:Array = [ADMIN, USER, GUEST];
// The static initializer needed to stop anyone else to an instance of this class
static private var INIT:Boolean = init();
// Class vars
private var _name:String;
private var _weight:int;
// Class constructor
public function UserRole(name:String, weight:int)
{
if(INIT)
{
throw new Error('UserRole enums already created');
}
this._name = name;
this._weight = weight;
}
// Returns the true weight of the class
public function valueOf():int
{
return this._weight;
}
// Returns a string when needed
public function toString():String
{
return this._name;
}
// Static initializer function
static private function init():Boolean
{
return true;
}
}
}
Let’s go through this class quickly. First, we have our 3 enums as static constants being an instance of the UserRole class. The constructor takes in a name and a weight which it stores for later functions with the class. There’s also an array of those static constants for easy referencing if you ever need to display them somewhere (like in a combobox for example). The next static variable (INIT) is what might confuse most people. This is called a static initializer; it is called only once after the class is loaded by the AVM which means the function will only be called after the constants are created. Static initializers call a function to get a certain value, but for the most part it just returns a Boolean to indicated the completion of the class loading or to set properties in the class. In this particular case, we need to know when the class is completed so that when a developer tries to recreate an instance of this class outside of the enum variables, it will throw an error.
With our enum created, let’s create a ‘User’ class that will use it.
package com.codemonkeycreative.model.entity
{
import com.codemonkeycreative.enums.UserRole;
public class User
{
private var _role:UserRole;
public function get role():UserRole
{
return this._role;
}
public function User(role:UserRole)
{
this._role = role
}
}
}
This is a simple class that takes in a UserRole for the constructor. Now we just need to add a line of code to create a user with a specific role.
var user:User = new User(UserRole.ADMIN);
Now, say if we were to forget that we had this enum and tried to create a new instance of the UserRole class outside of itself.
var user:User = new User(new UserRole('new role', 5));
This will undoubtedly create an error on runtime that will report that “UserRole enums already created”. And that’s how you create a proper enumerated data type in Actionscript. It is slightly complex at first, but once implemented, it does help a developer quite a bit throughout the coding process. It can also be used with MXML states to create powerful components, you just need to bind the ‘currentState’ property to the enum used, and then specify the enums in the state name. Here’s an example using the ‘UserRole’ enum.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" currentState="{user.role}">
<mx:Script>
<![CDATA[
import com.codemonkeycreative.enums.UserRole;
import com.codemonkeycreative.model.entity.User;
[Bindable]
private var user:User = new User(UserRole.ADMIN);
]]>
</mx:Script>
<mx:states>
<mx:State name="{UserRole.ADMIN}">
<mx:AddChild>
<mx:Label text="Welcome Admin" />
</mx:AddChild>
</mx:State>
<mx:State name="{UserRole.USER}">
<mx:AddChild>
<mx:Label text="Welcome User" />
</mx:AddChild>
</mx:State>
<mx:State name="{UserRole.GUEST}">
<mx:AddChild>
<mx:Label text="Please Login" />
</mx:AddChild>
</mx:State>
</mx:states>
</mx:Application>
As you can see, it can be very powerful, so use it accordingly. Please feel free to deliberate over this method or debate about the enums themselves.
Copyright © Thinking in Code. All Rights Reserved. Powered by Wordpress
This is a neat way going about it. May I ask, what are your thoughts on putting a conditional with the User constructor itself ? Granted, that way would be more “hacky” but could it do the job in theory?
Not sure I follow as to what you mean by ‘putting a conditional with the User constructor itself’. Do you mean resembling a SingletonEnforcer instance?