我想共享一个数组,所有类都可以“获取”并“更改”该数组中的数据。类似全局数组或多重访问数组的东西。如何使用ActionScript 3.0实现这一目标?
答案 0 :(得分:6)
有几种方法可以解决这个问题。一种是使用全局变量(如unkiwii的回答中所述),但这在ActionScript中并不是一种非常常见的方法。更常见的方法是:
创建一个名为DataModel
或类似的类,并将该类的数组变量定义为static:
public class DataModel {
public static var myArray : Array = [];
}
然后,您可以使用DataModel.myArray
从应用程序的任何部分访问此内容。这很少是一个很好的解决方案,因为(就像全局变量一样)应用程序的某个部分无法知道应用程序的另一部分何时修改了数组的内容。这意味着即使您的数据输入GUI将一个对象添加到数组,您的数据列表GUI也不会知道显示新数据,除非您实现了一些告诉它重绘的方法。
另一种方法是创建一个名为ArraySingleton的类,它包装实际的数组并为其提供访问方法,并且可以使用将单个实例保存在静态变量中的非常常见的单例模式来访问其实例。 / p>
public class ArraySingleton {
private var _array : Array;
private static var _instance : ArraySingleton;
public static function get INSTANCE() : ArraySingleton {
if (!_instance)
_instance = new ArraySingleton();
return _instance;
}
public function ArraySingleton() {
_array = [];
}
public function get length() : uint {
return _array.length;
}
public function push(object : *) : void {
_array.push(object);
}
public function itemAt(idx : uint) : * {
return _array[idx];
}
}
此类包装数组,可以通过ArraySingleton.INSTANCE
访问单个实例。这意味着你可以这样做:
var arr : ArraySingleton = ArraySingleton.INSTANCE;
arr.push('a');
arr.push('b');
trace(arr.length); // traces '2'
trace(arr.itemAt(0)); // trace 'a'
这样做的好处是,您可以在添加项目时或在以任何其他方式修改阵列时调度事件,以便可以向应用程序的所有部分通知此类更改。您可能希望通过实现更多类似于数组的接口来扩展上面的示例,例如pop(),shift(),unshift()等。
大规模应用程序开发中的一种常见模式称为依赖注入,基本上意味着通过以某种方式标记您的类(经常使用AS3元数据),您可以发信号通知框架应该“注入”引用那个班。这样,该类不需要关心引用的来源,但框架将确保它在那里。
AS3非常流行的DI框架是Robotlegs。
答案 1 :(得分:2)
注意:我不鼓励使用全局变量!
但这是你的回答
您可以转到默认包并使用全局变量的同名 创建 文件,并将全局变量设置为public:
//File: GlobalArray.as
package {
public var GlobalArray:Array = [];
}
就是这样!你有一个全局变量。您可以从您的代码(从任何地方)访问,如下所示:
function DoSomething() {
GlobalArray.push(new Object());
GlobalArray.pop();
for each (var object:* in GlobalArray) {
//...
}
}
答案 2 :(得分:1)
由于这个问题最近已被链接,我还会添加一些东西。我被提议使用单身之前的年龄,并且一旦我意识到命名空间和引用如何工作以及基于全局变量拥有所有内容都是坏主意,就会立即使用它。
注意 这只是一个展示,我建议您不要在整个地方使用此类方法。
至于单身人士的替代方案,您可以:
public class Global {
public static const myArray:Alternative = new Alternative();
}
并且几乎像单身人士一样使用它:
var ga:Alternative = Global.myArray;
ga.e.addEventListener(GDataEvent.NEW_DATA, onNewData);
ga.e.addEventListener(GDataEvent.DATA_CHANGE, onDataChange);
ga.push(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "ten");
trace(ga[5]); // 5
你的 Alternative.as 看起来与单身人士相似:
package adnss.projects.tchqs
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
public class Alternative extends Proxy
{
private var _data:Array = [];
private var _events:AltEventDisp = new AltEventDisp();
private var _dispatching:Boolean = false;
public var blockCircularChange:Boolean = true;
public function Alternative() {}
override flash_proxy function getProperty(id:*):* {var i:int = id;
return _data[i += (i < 0) ? _data.length : 0];
//return _data[id]; //version without anal item access - var i:int could be removed.
}
override flash_proxy function setProperty(id:*, value:*):void { var i:int = id;
if (_dispatching) { throw new Error("You cannot set data while DATA_CHANGE event is dipatching"); return; }
i += (i < 0) ? _data.length : 0;
if (i > 9 ) { throw new Error ("You can override only first 10 items without using push."); return;}
_data[i] = value;
if (blockCircularChange) _dispatching = true;
_events.dispatchEvent(new GDataEvent(GDataEvent.DATA_CHANGE, i));
_dispatching = false;
}
public function push(...rest) {
var c:uint = -_data.length + _data.push.apply(null, rest);
_events.dispatchEvent(new GDataEvent(GDataEvent.NEW_DATA, _data.length - c, c));
}
public function get length():uint { return _data.length; }
public function get e():AltEventDisp { return _events; }
public function toString():String { return String(_data); }
}
}
import flash.events.EventDispatcher;
/**
* Dispatched after data at existing index is replaced.
* @eventType adnss.projects.tchqs.GDataEvent
*/
[Event(name = "dataChange", type = "adnss.projects.tchqs.GDataEvent")]
/**
* Dispatched after new data is pushed intwo array.
* @eventType adnss.projects.tchqs.GDataEvent
*/
[Event(name = "newData", type = "adnss.projects.tchqs.GDataEvent")]
class AltEventDisp extends EventDispatcher { }
Singleton的唯一区别是你实际上可以拥有这个类的多个实例,所以你可以像这样重用它:
public class Global {
public static const myArray:Alternative = new Alternative();
public static const myArray2:Alternative = new Alternative();
}
有两个独立的全局数组,甚至可以同时将它作为实例变量。
注意强>
像这样包装数组使用像myArray.get(x)
或myArray[x]
这样的方法显然比访问原始数组慢(请参阅我们在setProperty
处采取的所有其他步骤。)
public static const staticArray:Array = [1,2,3];
另一方面,你无法控制这一点。并且可以在任何地方更改阵列的内容。
我必须补充一点,如果你想让事件以这种方式访问数据,你应该小心。与每个锋利的刀片一样,它很容易被切割。 例如,考虑一下这样做会发生什么:
private function onDataChange(e:GDataEvent):void {
trace("dataChanged at:", e.id, "to", Global.myArray[e.id]);
Global.myArray[e.id]++;
trace("new onDataChange is called before function exits");
}
在更改数组中的数据之后调用该函数,并在该函数内部再次更改数据。基本上它类似于做这样的事情:
function f(x:Number) {
f(++x);
}
如果您切换myArray.blockCircularChange
,您可以看到在这种情况下会发生什么。有时你会故意想要这样的递归,但很可能你会偶然地做到这一点#34;不幸的是,闪存会突然停止这样的事件调度,甚至没有告诉你原因,这可能会令人困惑。
下载完整示例 here
我想在互联网上有很多关于这一点的信息,但为了完整,我将添加简单的例子。
假设您在应用中有一些视图,其中显示一些文字,图形或最可能的游戏内容。说你有国际象棋游戏。 Mayby你在两个类中分离了逻辑和图形,但是你想要两个都在相同的棋子上运行。因此,您可以创建Global.pawns
变量,并在Grahpics
和Logic
类中使用该变量。
一切都是randy-dandy,完美无瑕。现在你有了一个好主意 - 添加选项让用户一次玩两场比赛甚至更多。您所要做的就是创建另一个匹配实例......对吗?
此时你注定要失败,因为你班级的每个实例都会使用相同的Global.pawns
数组。您不仅要将此变量设置为全局变量,而且还限制自己仅使用使用此变量的每个类的单个实例:/
因此,在使用任何全局变量之前,如果要存储在其中的事物在整个应用程序中真正是全局的并且是通用的,那么请三思而后行。