2011年10月15日 星期六

判斷對象為「物件」

這個標題起得有些奇怪,依照大多數物件導向的理論中,Object 類別是所有的類別的「根」,也就是說,除了一些基本型態的變數(如︰int, float…等),所有類別都是 Object 的子類別。不過,偏偏就讓我遇到一個得判斷「純 Object」的狀況。

事情是這樣子的,我所負責的專案中間有一個編碼/解碼的功能,採用 JSON 格式的字串進行資料儲存。依照「測試驅動開發」的思維,得作一個測試程式,來判斷解碼後可以得到和原始資料完全相同的內容,因此放入假資料開始撰寫程式。

一開始我思考到,JSON 字串通常是用來存放值名對,或是陣列的資料。而身為制定 JSON 格式的自己,很清楚不會放入其它奇怪的資料型態,只要比對每一個鍵值和所包含的內容即可。因此我的第一版程式沒有花費太多時間就寫出來了。

後來由於要編碼的內容變得複雜,得放入數量不固定的多筆資料。因此 JSON 的內容,由原來的值名對 + 基本型態,又多加上了陣列 Array。由於 Array 也是一種物件,所以兩個陣列必須進入的迴圈對每一個元素進行比對,若是直接使用「A == B」則為因為 Array 存放在的記憶體位置不同,而總是得到 false 的結果。它讓我花了一些時間作思考,最後決定使用遞迴的方式進行,以免出現陣列之中間又出現陣列。

再過不久,我發覺資料變得更加複雜,必須得在陣列或是屬性中加入另外的 Object 類別,在 JSON 格式中是被允許的,不過對於我的測試、檢查程式來說,就是一場災難。其中最糟的一點是 Flash AcrionScript 語法中,基本型態也是 Object 的子類別。因此底下的判斷為真…
1 is Object

因為骨子裡,「1」是一個「Number」類別的物件,這個發現真是讓意外。

在 JSON 的儲存之中, Array 裡的內容是有順序性的,所以我可以利用迴圈一個一個比對,而 Object 的內容,本身值名對的特性導致它具有容許屬性順序不同的狀況,因此雖然曾經想過將資料轉成 JSON 格式字串,再作字串比對。就因為屬性順序不同,可能導致相同資料輸出不同結果字串,只好作罷。

換句話說,我不能使用「物件 is 類別」的語法來找出「純粹的物件」,而也不想寫長長一堆判斷式,去過濾掉 Array 和其它基本型態,還好終於找到「ObjectUtil」這個類別,其中有一個靜態方法叫作「isDynamicObject」,將 Object 放入就可以捕捉出「純物件」,再來就是使用「for...in...」語法一個一個屬性比對。

為什麼我認為 isDynamicObject 可以滿足我的要求呢?因為我記得的純大部分的變數是不能在執行過程式增加屬性或方法,而 Object 是例外。我在 FLEX 就是使用這個特性,製作出一個很大的 Object 再轉換成 JSON 格式字串。因此,isDynamicObject 可以幫我濾掉其它基本型別的資料。

為了這個功能花了我幾個小時才試出來,留個文章作個記錄…

後記,打文章的時候,忽然想到 Array 似乎也是可以動態加入屬性,因為底下這段程式是可以運作的…
var testAry:Array = new Array();
testAry["key1"] = "value1";
雖然這不是 Array 的正規用法,但是也表示它有可能是 dynamicObject 的一種,趕快寫個程式試看看…
trace("Array is Dynamic Object? "+ObjectUtil.isDynamicObject(new Array()));
結果得到 true 的傳回值。

也因此我又回頭修改我的程式,確定將 is Array 判斷放在 ObjectUtil.isDynamicObject 之前,確保 Array 不會被當作 Object 處理,雖然不會有太大的問題啦~還是可以判斷,不過總是覺得怪怪的。

沒有留言:

張貼留言