ActionScript 3
Verwendung der Proxy-Klasse
Suche…
Einführung
Zuerst muss ich sagen. Es gibt einen Grund, warum diese Proxy-Sache trotz ihres scheinbaren Nutzens im Internet nicht genug hervorgehoben wird.
Sie können es nicht verwenden, um eine zufällige Eigenschaft einer zufälligen Klasse / Instanz zu überwachen. Sie können diese Technik nur durch die Unterklasse der Proxy- Klasse verwenden.
Einige Operationen erwarten keine Ausnahmen. Sie müssen also vollständig verstehen, was Sie tun und warum Sie es tun, und Ihr Code muss absolut sauber und fehlerfrei sein.
Implementierung
Die andere Sache über die Proxy-Klasse und warum sie nicht so beliebt ist, ist, dass es ziemlich schwierig ist, ein Problem zu ergründen, das genau eine dynamische Klasse mit einem kontrollierbaren Zugriff auf seine dynamischen Eigenschaften und Methoden als am besten geeignete Lösung benötigt. Jedes Mal, wenn ich versuchte, Proxy zu verwenden, habe ich auf etwas anderes zurückgegriffen, das einfacher und kontrollierbarer ist.
Lassen Sie uns jedoch nicht entmutigen. Ich mag die Idee, die letzten Array-Elemente mit [-1], [-2] usw. Indizes in Python anzusprechen. Vielleicht keine große Leistung, aber es fühlt sich gut an, das eher als langes und unbeholfenes someArray [someArray.length - 1] zu verwenden . Mal sehen, was wir dagegen tun können.
package
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
/**
* Pyaray the Tentacled Whisperer of Impossible Secrets.
*/
dynamic public class PyArray extends Proxy
{
private var data:Array;
public function PyArray(...args:Array)
{
if (args.length == 0)
{
data = new Array;
}
else if ((args.length == 1) && (args[0] is Array))
{
data = args[0];
}
else
{
data = args;
}
}
// This is a getter proxy to all the available Array
// elements and properties and, sometimes, methods.
override flash_proxy function getProperty(name:*):*
{
var anIndex:int = name;
// Handle the int indices of the Array elements.
if (anIndex == name)
{
// Handle the -1, -2, etc indexing.
if (anIndex < 0) anIndex += data.length;
if (anIndex >= data.length) return null;
if (anIndex < 0) return null;
return data[anIndex];
}
// Handle the existing public Array properties.
if (data.hasOwnProperty(name)) return data[name];
// Handle the Array methods addressed via ["member"] access.
try
{
if (data[name] is Function) return data[name];
else throw new Error;
}
catch (fail:Error)
{
trace("[PyArray] is unable to resolve property \"" + name + "\".");
}
return null;
}
// This will set either elements, or settable properties.
override flash_proxy function setProperty(name:*, value:*):void
{
var anIndex:int = name;
// Handle the int indices of the Array elements.
if (anIndex == name)
{
// Handle the -1, -2, etc indexing.
if (anIndex < 0) anIndex += data.length;
// In case the element index is out of range,
// the PyArray will extend its data Array.
// if (anIndex >= data.length) return;
if (anIndex < 0) return;
data[anIndex] = value;
return;
}
// Handle the existing (or dynamic) public Array properties.
try
{
data[name] = value;
}
catch (fail:Error)
{
trace("[PyArray] is unable to set property \"" + name + "\".");
}
return;
}
// This allows to delete PyArray elements with "delete" operator.
override flash_proxy function deleteProperty(name:*):Boolean
{
var anIndex:int = name;
// Handle the int indices of the Array elements.
if (anIndex == name)
{
// Handle the -1, -2, etc indexing.
if (anIndex < 0) anIndex += data.length;
if (anIndex >= data.length) return false;
if (anIndex < 0) return false;
data.splice(anIndex, 1);
return true;
}
// Handle the dynamic public Array properties.
try
{
delete data[name];
return true;
}
catch (fail:Error)
{
trace("[PyArray] is unable to delete the \"" + name + "\" property.");
}
return false;
}
// This proxies any attempt to call a method on PyArray directly to data Array, thus
// all Array methods (including "toString" method called through trace) are available.
override flash_proxy function callProperty(name:*, ...rest):*
{
try
{
return (data[name] as Function).apply(data, rest);
}
catch (fail:Error)
{
trace("[PyArray] is unable to resolve method \"" + name + "\".");
return null;
}
}
// This allows PyArray to handle for..in and for..each..in loops.
// The initial call starts with zero, so we need to do this +1 -1 magic
// in order for enumeration to work correctly. I'm not happy with this either.
override flash_proxy function nextNameIndex(index:int):int
{
if (index >= data.length) return 0;
else return index + 1;
}
// This method handles the for..in loop.
override flash_proxy function nextName(index:int):String
{
return (index - 1).toString();
}
// This method handles the for..each..in loop.
override flash_proxy function nextValue(index:int):*
{
return data[index - 1];
}
}
}
Verwendungszweck
package
{
import flash.display.Sprite;
/**
* Daemonette of Slaanesh.
*
* It is minor female demon, vaguely human-like, but with crab-like pincers instead of hands.
* She wears a rather indecent skimpy leather bikini, moves quickly and casts deadly spells!
*/
public class Slaanesh extends Sprite
{
public function Slaanesh()
{
// Lets initialize the PyArray.
var PA:PyArray = new PyArray(1,2,3,4,5,4,3,2,1,"Foo");
// Basic check: get the last element.
trace(PA[-1]);
// output:
// Foo
// This will map to the 0-based third element.
trace(PA[2.0]);
// output:
// 3
// This should not get us anywhere.
trace(PA[2.1]);
// output:
// [PyArray] is unable to resolve property "2.1".
// null
// This should return the length of the data Array.
trace(PA["length"]);
// output:
// 10
// This should return the length of the data Array.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.length);
// output:
// 10
// This will map to indexOf method of data Array via getProperty method.
trace(PA["indexOf"]);
// output:
// function Function() {}
// This will map to indexOf method of data Array via getProperty method.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.indexOf);
// output:
// function Function() {}
// This is a try to access a non-existent property.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.P124);
// output:
// [PyArray] is unable to resolve property "P124".
// null
// This is a try to call a non-existent method via callProperty method.
// This will not compile unless PyArray class is marked "dynamic".
trace(PA.P124());
// output:
// [PyArray] is unable to resolve method "P124".
// null
// Basic check: calling a proxied method via callProperty method.
trace(PA.indexOf(5));
// output:
// 4
// An attempt to replace an Array method with a random value.
// This will not compile unless PyArray class is marked "dynamic".
PA.indexOf = 123;
// output:
// [PyArray] is unable to set property "indexOf".
// An attempt to assign a random value to a random property.
// It will succees because Array, as a dynamic class, allows so.
// This will not compile unless PyArray class is marked "dynamic".
PA.indexOfz = 123;
trace(PA.indexOfz);
// output:
// 123
// An attempt to assign an Array element via negative indexing.
// This trace works fine because toString method is also proxied.
PA[-3] = "Hello";
trace(PA);
// output:
// 1,2,3,4,5,4,3,Hello,1,Foo
// An attempt to delete Array elements via normal and negative indexing.
// This operation is mapped via deleteProperty method.
delete PA[-4]; // deletes "3" before "Hello"
delete PA[0]; // deletes "1" at the start.
trace(PA);
// output:
// 2,3,4,5,4,Hello,1,Foo
// An attempt to delete a non-dynamic method reference.
// There's no error output, AS3 must be handling this internally.
delete PA.indexOf;
trace(PA.indexOf);
// output:
// function Function() {}
// An attempt to set an element out of index range.
PA[10] = "123abc";
trace(PA);
// output:
// 2,3,4,5,4,Hello,1,Foo,,,123abc
var aText:String;
// This is a test of for..in loop, Array elements are
// enumerated via nextName and nextNameIndex methods.
aText = ""
for (var aKey:String in PA)
aText += aKey + ":" + PA[aKey] + " ";
trace(aText);
// output:
// 0:2 1:3 2:4 3:5 4:4 5:Hello 6:1 7:Foo 8:undefined 9:undefined 10:123abc
// This is a test of for..each..in loop, Array elements are
// enumerated via nextValue and nextNameIndex methods.
aText = "";
for each (var aValue:* in PA)
aText += aValue + " ";
trace(aText);
// output:
// 2 3 4 5 4 Hello 1 Foo undefined undefined 123abc
}
}
}