ActionScript 3 中的对象序列化
2008-11-12 09:06 宝宝合凤凰 阅读(1436) 评论(0) 编辑 收藏 举报
我们都知道对象序列化的目的是为了对象能够在网络上传输,以便存储对象,这是很有用处的,比如一个在线Flash游戏,玩家玩到一半想明天再玩,这时需要通过对象序列化把游戏数据保存起来,不然关闭浏览器数据就都没了,又要从头开始,当然利用Flash中的LSO也可以进行存储数据,不过是存在客户端上,这样的数据不一定能持久,对象序列化的主要目的是保存到服务器的数据库里,也许有人会问,干嘛不把对象的属性直接保存到数据库,还这么麻烦饶一大圈,这当然可以,但是如果对象的属性非常多,写起来会不会很繁琐呢,不如直接把对象保存起来这样反而跟简便,对象序列化的原理是把对象转换为字符串的形式,因为字符串任何语言都认识都能处理,而对象类型只能是属于特定的语言,比如一个Rectangle实例有width,height,fillColor,lineColor属性,把它转换为字符串格式后:"width=value|height=value|fillColor=value|lineColor=value"。
ActionScript 3本身并没有提供对象序列化的APIs,因为它已经有了flash remoting(AMF协议),AMF协议完成对象的序列化和反序列化,这里我们先不谈AMF,看看如何自定义实现对象的序列化,OReilly.Essential.ActionScript.3.0的作者提供了一系列类和接口来实现对象序列化,我们看看他是如何做的:
定义了一个Serializable接口,只声明一个方法用于对象的序列化:
定义一个实现Serializable接口的Serializer类,用于完成对象
一个继承Serializer的Point类,我们将对Point类实例进行序列化处理:
测试类,输出结果为:y=6,x=5
我们看到已经成功把Point对象变成字符串“y=6,x=5”,我们再来看一个例子:
Shape类,定义了两个属性fillColor,lineColor:
Rectangle类继承Shape,同时实现Serializable接口:
一个类要想能够被序列化,要么实现Serializable接口,要么继承已经实现Serializable接口的类,因为Rectangle类的父类没有实现Serializable接口,所以Rectangle类必须实现Serializable接口,而上面那个Point类的父类已经实现Serializable接口,等于是间接实现了,我们看到Rectangle类的serialize()方法,把Serializer当作序列化工具,对Rectangle对象进行序列化处理, 对于核心类Serializer作者设计的比较巧妙,能同时处理两种情况的序列化。
最后还是要说一下一个小问题,假如序列化后的字符串保存到数据库了,再读取进行反序列化时,该怎么知道这些字符串是什么类的呢??? 我的想法是在序列化时同时保存类名以便为反序列化做准备,拿Point例子来说:
增加一个属性代表类名:
ActionScript 3本身并没有提供对象序列化的APIs,因为它已经有了flash remoting(AMF协议),AMF协议完成对象的序列化和反序列化,这里我们先不谈AMF,看看如何自定义实现对象的序列化,OReilly.Essential.ActionScript.3.0的作者提供了一系列类和接口来实现对象序列化,我们看看他是如何做的:
定义了一个Serializable接口,只声明一个方法用于对象的序列化:
package serializer
{
public interface Serializable
{
function serialize():String;
}
}
{
public interface Serializable
{
function serialize():String;
}
}
定义一个实现Serializable接口的Serializer类,用于完成对象
package serializer
{
public class Serializer implements Serializable
{
private var serializationVars:Array; //存储对象的属性
private var serializationObj:Serializable; //指向可序列化的对象引用
private var recordSeparator:String; //指定属性之间的分隔符
public function Serializer(){
setSerializationObj(this);
}
public function setSerializationVars(vars:Array):void{
serializationVars = vars;
}
public function setSerializationObj(obj:Serializable):void{
serializationObj = obj;
}
public function setRecordSeparator(rs:String):void{
recordSeparator = rs;
}
public function serialize():String
{
var s:String = "";
for (var i:int = serializationVars.length; --i >= 0;){
s += serializationVars[i] + "=" + String(serializationObj[serializationVars[i]]);
if(i>0){
s += recordSeparator;
}
}
return s;
}
}
}
{
public class Serializer implements Serializable
{
private var serializationVars:Array; //存储对象的属性
private var serializationObj:Serializable; //指向可序列化的对象引用
private var recordSeparator:String; //指定属性之间的分隔符
public function Serializer(){
setSerializationObj(this);
}
public function setSerializationVars(vars:Array):void{
serializationVars = vars;
}
public function setSerializationObj(obj:Serializable):void{
serializationObj = obj;
}
public function setRecordSeparator(rs:String):void{
recordSeparator = rs;
}
public function serialize():String
{
var s:String = "";
for (var i:int = serializationVars.length; --i >= 0;){
s += serializationVars[i] + "=" + String(serializationObj[serializationVars[i]]);
if(i>0){
s += recordSeparator;
}
}
return s;
}
}
}
一个继承Serializer的Point类,我们将对Point类实例进行序列化处理:
package serializer
{
public class Point extends Serializer
{
public var x:Number;
public var y:Number;
public var name:String = "Point";
public function Point(x:Number,y:Number)
{
super();
setRecordSeparator(","); //设置分隔符
setSerializationVars(["x","y"]); //序列化x,y属性
this.x = x;
this.y = y;
}
}
}
{
public class Point extends Serializer
{
public var x:Number;
public var y:Number;
public var name:String = "Point";
public function Point(x:Number,y:Number)
{
super();
setRecordSeparator(","); //设置分隔符
setSerializationVars(["x","y"]); //序列化x,y属性
this.x = x;
this.y = y;
}
}
}
测试类,输出结果为:y=6,x=5
package
{
import flash.display.Sprite;
import serializer.Point;
import serializer.Rectangle;
import serializer.Rectangle;
public class TestSerialization extends Sprite
{
public function TestSerialization()
{
super();
var p:Point = new Point(5,6);
trace(p.serialize());
}
}
}
{
import flash.display.Sprite;
import serializer.Point;
import serializer.Rectangle;
import serializer.Rectangle;
public class TestSerialization extends Sprite
{
public function TestSerialization()
{
super();
var p:Point = new Point(5,6);
trace(p.serialize());
}
}
}
我们看到已经成功把Point对象变成字符串“y=6,x=5”,我们再来看一个例子:
Shape类,定义了两个属性fillColor,lineColor:
package serializer
{
public class Shape
{
public var fillColor:uint = 0xFFFFFF;
public var lineColor:uint = 0;
public function Shape(fillColor:uint,lineColor:uint){
this.fillColor = fillColor;
this.lineColor = lineColor;
}
}
}
{
public class Shape
{
public var fillColor:uint = 0xFFFFFF;
public var lineColor:uint = 0;
public function Shape(fillColor:uint,lineColor:uint){
this.fillColor = fillColor;
this.lineColor = lineColor;
}
}
}
Rectangle类继承Shape,同时实现Serializable接口:
package serializer
{
public class Rectangle extends Shape implements Serializable
{
public var width:Number = 0;
public var height:Number = 0;
public function Rectangle(fillColor:uint, lineColor:uint)
{
super(fillColor, lineColor);
}
public function setSize(w:Number,h:Number):void{
width = w;
height = h;
}
public function getArea():Number{
return width*height;
}
public function serialize():String
{
var ser:Serializer = new Serializer();
ser.setRecordSeparator("|");
ser.setSerializationVars(["height","width","fillColor","lineColor"]);
ser.setSerializationObj(this);
return ser.serialize();
}
}
}
{
public class Rectangle extends Shape implements Serializable
{
public var width:Number = 0;
public var height:Number = 0;
public function Rectangle(fillColor:uint, lineColor:uint)
{
super(fillColor, lineColor);
}
public function setSize(w:Number,h:Number):void{
width = w;
height = h;
}
public function getArea():Number{
return width*height;
}
public function serialize():String
{
var ser:Serializer = new Serializer();
ser.setRecordSeparator("|");
ser.setSerializationVars(["height","width","fillColor","lineColor"]);
ser.setSerializationObj(this);
return ser.serialize();
}
}
}
一个类要想能够被序列化,要么实现Serializable接口,要么继承已经实现Serializable接口的类,因为Rectangle类的父类没有实现Serializable接口,所以Rectangle类必须实现Serializable接口,而上面那个Point类的父类已经实现Serializable接口,等于是间接实现了,我们看到Rectangle类的serialize()方法,把Serializer当作序列化工具,对Rectangle对象进行序列化处理, 对于核心类Serializer作者设计的比较巧妙,能同时处理两种情况的序列化。
最后还是要说一下一个小问题,假如序列化后的字符串保存到数据库了,再读取进行反序列化时,该怎么知道这些字符串是什么类的呢??? 我的想法是在序列化时同时保存类名以便为反序列化做准备,拿Point例子来说:
增加一个属性代表类名:
package serializer
{
public class Point extends Serializer
{
public var x:Number;
public var y:Number;
public var name:String = "Point";
public function Point(x:Number,y:Number)
{
super();
setRecordSeparator(",");
setSerializationVars(["x","y","name"]);
this.x = x;
this.y = y;
}
}
}
{
public class Point extends Serializer
{
public var x:Number;
public var y:Number;
public var name:String = "Point";
public function Point(x:Number,y:Number)
{
super();
setRecordSeparator(",");
setSerializationVars(["x","y","name"]);
this.x = x;
this.y = y;
}
}
}
registeregisterClassAlias的用法
registerClassAlias在利用AMF3进行序列话网络通讯中,是非常有用的。需要把客户端的对象直接传送到服务器得时候,保留该对象的类(类型)。 这样的话,就可以传送自定义对象或者系统自带对象。
具体的使用方法,官方有详细地用法。这里我只说说自己的一些理解。
readObject方法对构造器有参数的类,是会出错的,会弹出参数数量不匹配这个错误。因为还原对象进行反射的时候,是默认没有参数的给构造器的。这也是有些人 讨论Sprite等对象不能进行深度拷贝的原因
所以在使用AMF3进行序列话的时候要注意这个了,还有一个就是,如果那个类包含了多个类,也就是个复合类,那么里面的那个复合类,也必须进行registerClassAlias,例如
- package
- {
- import flash.geom.Point;
- public class Test
- {
- public var name:String;
- public var point:Point;
- }
- }
- 这样需要写两条语句才能完全把Test序列化
- registerClassAlias("point",Point);
- registerClassAlias("test",Test)
具体使用例子,参考官方例子,下面是摘录出来的
此示例使用 registerClassAlias() 函数为 ExampleClass 注册一个别名 ( com.example.eg )。 由于为类注册了别名,因此可以将对象作为 ExampleClass 的实例反序列化,且代码将输出 true。 如果删除 registerClassAlias() 调用,则代码将输出 false
- package {
- import flash.display.Sprite;
- import flash.net.registerClassAlias;
- import flash.utils.ByteArray;
- public class RegisterClassAliasExample extends Sprite {
- public function RegisterClassAliasExample() {
- registerClassAlias("com.example.eg", ExampleClass);
- var eg1:ExampleClass = new ExampleClass();
- var ba:ByteArray = new ByteArray();
- ba.writeObject(eg1);
- ba.position = 0;
- var eg2:* = ba.readObject();
- trace(eg2 is ExampleClass); // true
- }
- }
- }