今天在天地会看见一篇帖子,关于深度拷贝对象的,很有感触,于是自己又就此做了一些细致的研究。原帖:
我们重点讨论一个数据对象的拷贝,而非显示对象的拷贝,因为Flash的显示对象是无法做到真正的深度拷贝的。
这里说的数据对象呢,一般是一个存储数据的VO类对象。
相信大部分人都知道用下面这种方法来进行对象的拷贝。
常规方法,简单,但不全面.
public function clone(sourceObj:*):*
{
var b:ByteArray = new ByteArray();
b.writeObject(sourceObj);
b.position = 0;
return b.readObject();
}
文章开始提到的天地会的帖子的方法有所改进,但是也有弊端,对于类里的对象(复合类对象)无法做到拷贝,于是我重新写了一个方法,能够完全的拷贝对象里的除显示对象以外的所有数据型变量。(至少经过测试,目前我是这么认为,如果有相左的发现,请告知,不胜感激)
代码如下:
package com.gdlib.util
{
import flash.net.registerClassAlias;
import flash.utils.ByteArray;
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getTimer;
/**
* Object 工具类.
* @author Jack
* Email: lovewqcm520@gmail.com
*/
public class ObjectUtil
{
private static var aliasList:Array = [];
/**
* 复制一个对象
* @param sourceObj 要复制的源对象
* @param deep 是否对对象进行AMF序列化以后再深度复制
* @return
*/
public static function clone(sourceObj:*, deep:Boolean=true):*
{
if(!sourceObj)
return null;
var lastTime:Number = getTimer();
if(deep)
{
// 得到 sourceObj的类名
var qualifiedClassName:String = getQualifiedClassName(sourceObj);
if(aliasList.indexOf(qualifiedClassName) == -1)
{
// e.g com.gdlib.test::RegisterClassAliasTest
var packageName:String = qualifiedClassName.replace("::", ".");
// 得到 sourceObj的类的类定义
var classType:Class = getDefinitionByName(qualifiedClassName) as Class;
// 注册此别名和类
if(classType)
{
registerClassAlias(packageName, classType);
aliasList.push(qualifiedClassName);
trace("register class", packageName);
}
// 注册类公共属性(如果是复合类)
registerVariables(sourceObj);
}
}
// 复制此对象
var b:ByteArray = new ByteArray();
b.writeObject(sourceObj);
b.position = 0;
trace("Clone object takes", getTimer()-lastTime, "ms.\n");
return b.readObject();
}
/**
* 注册某个类的公共属性(如果是复合类)所属的类的别名.
* @param sourceObj
*/
private static function registerVariables(sourceObj:*):void
{
// 注册类公共属性(如果是复合类)
var xml:XML = describeType(sourceObj);
var variable:XML;
var variableType:String;
var variablePackageName:String;
var variableClassType:Class;
var variableXml:XMLList;
if(sourceObj is Class)
variableXml = xml.factory.variable;
else
variableXml = xml.variable;
// <variable name="point" type="flash.geom::Point">
// <metadata name="__go_to_definition_help">
// <arg key="pos" value="209"/>
// </metadata>
// </variable>
// <variable name="name" type="String">
// <metadata name="__go_to_definition_help">
// <arg key="pos" value="142"/>
// </metadata>
// </variable>
for each (variable in variableXml)
{
variableType = variable.@type;
if(variableType.indexOf("::") != -1)
{
if(aliasList.indexOf(variableType) == -1)
{
// "flash.geom::Point" 转换为 "flash.geom.Point"
variablePackageName = variableType.replace("::", ".");
variableClassType = getDefinitionByName(variableType) as Class;
// 注册此别名和类
if(variableClassType)
{
registerClassAlias(variablePackageName, variableClassType);
registerVariables(variableClassType);
aliasList.push(variableType);
trace("register variable", variablePackageName);
}
}
}
}
}
}
}
使用方法:
var source:RegisterClassAliasTest = new RegisterClassAliasTest();
var result:RegisterClassAliasTest = ObjectUtil.clone(source);
trace(result is RegisterClassAliasTest);
缺点:为了达到较好的拷贝效果,此方法比较耗时,经过粗略测试,性能应该还能接受。
注意:复杂的显示对象(DisplayObject)无法达到真正的拷贝。
欢迎大家测试使用。