[教學]在AS3中使用列舉

Actionscript 3本身沒有列舉,所以在開發Flash專案時大都以常數宣告成整數或字串的方式來區分類別,雖然不會有問題,但在開發大型專案時,常數的宣告方法反而會成為維護上的大問題。

舉例來說,一般Flash中重覆使用變數會宣告成:

public class MoveDirection
{
        public static const UP:int = 0;
        public static const DOWN:int = 1;
        public static const LEFT:int = 2;
        public static const RIGHT:int = 3;
        
        public function MoveDirection()
        {
        }
}

假設在使用時以 function changeDirection(directionType:int):void 的方式調用,雖然使用上沒問題,但如果今天把程式碼交接給別人,在交接不清楚的情況下,directionType到底要填什麼才好,因為型態是int,所以只要是整數都可以填,在求快的情況下,有人可能就會直接填入1, 2, 3, 4,程式碼最後就充滿了魔術數字,愈來愈難維護。

為了避免上述問題,Adobe在文件上有提出一個簡單的作法,使用宣告自己的方式來固定型別,上面的程式可改寫成:

public class MoveDirection
{
        public static const UP:MoveDirection = new MoveDirection();
        public static const DOWN:MoveDirection = new MoveDirection();
        public static const LEFT:MoveDirection = new MoveDirection();
        public static const RIGHT:MoveDirection = new MoveDirection();
        
        public function MoveDirection()
        {
        }
}

在使用時會變成 function changeDirection(directionType:MoveDirection):void ,型態固定了,即使沒有說清楚也可以知道要填入什麼,也不必憺心會被順便亂填, 但這方法還是有問題,如果今天我的directionType是Server告訴我,而類型是以整數方式記載,那我要怎麼換成Client看得懂的列舉,這個方法沒有處理資料轉換的問題,在溝通上還是很難用,所幸網路上還是有不錯的第三方可用,as3Commons就有提供更完整的列舉類。

筆者自已也寫了一個簡單的列舉類別,功能簡單但有實作自動遞增

package idv.gd.utils
{
        import flash.utils.Dictionary;
        import flash.utils.getQualifiedClassName;
        
        import flashx.textLayout.formats.Direction;

        public class Enum
        {
                private static var _enums:Dictionary = new Dictionary();;
                
                private var _id:Object;
                
                public function Enum(id:Object = null)
                {
                        var className:String = getQualifiedClassName(this);
                        if (!_enums[className])
                                _enums[className] = new Dictionary();
                        
                        if (id == null)
                        {
                                id = largestID + 1;
                                if (id > uint.MAX_VALUE)
                                        throw new Error("id超過最大值");
                        }
                        
                        _id = id;
                        if (!_enums[className][id])
                                _enums[className][id] = this;
                        else
                                throw new Error("id值已存在");
                }
                
                /**
                 * 取得目前最大值索引 
                 * @return 
                 * 
                 */             
                private function get largestID():uint
                {
                        var className:String = getQualifiedClassName(this);
                        
                        var maxValue:uint = 0;
                        
                        var values:Dictionary = _enums[className];
                        
                        if (values)
                        {
                                for each (var enum:Enum in values)
                                {
                                        var enumID:uint = enum.idToUint();
                                        if (enumID > maxValue)
                                                maxValue = enumID;
                                }
                        }
                        
                        return maxValue;
                }
                
                /**
                 * 取得id物件 
                 * @return 
                 * 
                 */             
                public function get id():Object
                {
                        return _id;
                }
                
                /**
                 * 依id取得列舉實體  
                 * @param enumClass 要轉換的列舉類別
                 * @param id 識別id
                 * @return 
                 * 
                 */             
                public static function getEnumByID(enumClass:Class, id:Object):*
                {
                        var className:String = getQualifiedClassName(enumClass);
                        
                        var currentValues:Dictionary = _enums[className];
                        
                        return (currentValues) ? currentValues[id] : null;
                }
                
                /**
                 * id轉字串 
                 * @return 
                 * 
                 */             
                public function idToString():String
                {
                        return String(_id);
                }
                
                /**
                 * id轉正整數 
                 * @return 
                 * 
                 */             
                public function idToUint():uint
                {
                        return uint(_id);
                }
        }
}

使用上可以寫成:

public class MoveDirection extends Enum
{
        public static const UP:MoveDirection = new MoveDirection();//1
        public static const DOWN:MoveDirection = new MoveDirection();//2
        public static const LEFT:MoveDirection = new MoveDirection();//3
        public static const RIGHT:MoveDirection = new MoveDirection();//4
        
        public static const UP_LEFT:MoveDirection = new MoveDirection(1000);//1000
        public static const UP_RIGHT:MoveDirection = new MoveDirection();//1001
        public static const DOWN_LEFT:MoveDirection = new MoveDirection();//1002
        public static const DOWN_RIGHT:MoveDirection = new MoveDirection();//1003
        
        public function MoveDirection(id:Object=null)
        {
                super(id);
        }
}

索引也可為字串,但最好不要把數字跟字串混在同一類別,底層有實作轉換,可使用getEnumByID將識別索引轉成列舉實體,在溝通上會方便許多

下載原始碼

參考文章

Flash Help http://help.adobe.com/zh_TW/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f2f.html

0 意見 :: [教學]在AS3中使用列舉