在 ActionScript 中生成动态 proxy/decorator/encapsulator
Generating a dynamic proxy/decorator/encapsulator in ActionScript
我正在寻找一种方法来做这样的事情:
class ClassA
{
public function func1():void{}
}
class ClassB extends ClassA
{
public override function func1():void{
trace("middleman");
base.func1();
}
}
我知道代理 class,但我想要实现的是
var instance:ClassA = new ClassA();
instance = Modifier.messWith(instance); //returns instance with ClassB functionality, without ClassB being defined at compile time
我想要提供额外功能的 class 数量很高,我不想花所有时间为每个功能编写一个扩展 class。另一个用于不同的功能。有什么方法可以实现我正在尝试的目标吗?
编辑:
作为对答案的回应,这是整个事情的最终目标,因为我对这个问题有些混淆:
我需要一种生成动态代理的方法,类似于 Castle.DynamicProxy 在 C# 中所做的,以便创建我正在处理的远程调用概念库。现有的 Proxy class 完全符合我的要求,但有一个致命的缺点 - 它需要代理 class 来扩展 Proxy,这有两个缺点:
1) 我需要代理的所有 classes 都需要扩展代理,这在使用现有代码时会出现问题。
2) 如果一个对象只是简单地包装在一个代理的通用实现中(一个 class 代理一个随机 calasses 的函数调用并用它们做一些事情),该对象不能传递给具有强类型参数的现有函数,因为它没有正确的类型(代理或其扩展是唯一可能的类型)。
我认为你应该分享它的端点目标,因为你要求的东西对于 AS3 概念来说非常陌生。
尽管如此,但有一定的限制,它是可行的。
实施:
package assortie
{
public class Wrapper
{
// The public interface to wrap methods.
static public function wrap(target:Object, name:String, another:Function):void
{
var aWrapper:Wrapper = new Wrapper;
// Remember the wrapped object:method.
aWrapper.wrapped = target;
aWrapper.wrappee = target[name];
aWrapper.wrouter = another;
// Substitute it with the own method.
target[name] = aWrapper.delegateWrapper;
}
// A stacked list of active wrappers.
static private var list:Array = new Array;
// A wrapper method should call Wrapper.recall(...)
// to invoke the wrapped method.
static public function recall(...args:Array):*
{
var result:*;
var aWrapper:Wrapper = list[list.length - 1];
if (aWrapper)
{
result = aWrapper.wrappee.apply(aWrapper.wrapped, args);
}
return result;
}
private var wrapped:Object;
private var wrappee:Function;
private var wrouter:Function;
private function delegateWrapper(...args:Array):*
{
// Register self as the last activated wrapper.
list.push(this);
var result:*;
result = wrouter.apply(wrapped, args);
// Remove self from the active wrappers' list.
while (list.indexOf(this) > 0)
{
list.splice(list.indexOf(this), 1);
}
return result;
}
}
}
用法:
package assortie
{
import assortie.Wrapper;
import flash.display.Sprite;
public class MixIn extends Sprite
{
public var a:int = 1;
public function MixIn()
{
// See internal class at the bottom.
var aMix:MeexEen = new MeexEen;
// You can stack the wrappers.
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
trace("The Power of Mixing In:", power());
// Outputs:
// 2
// 3
// 4
// 5
// 6
// The Power of Mixing In: 720
}
// The method to be wrapped should be declared as variable.
// It is not possible to replace a properly declared method.
public var power:Function = function ():int
{
return 1;
}
}
}
import assortie.Wrapper;
// Should be either dynamic or contain the declarations
// of all the variables accessed through "this".
internal dynamic class MeexEen
{
// The wrapping method should be declared as closure.
// Outherwise the method is bound to its original
// instance and it is not possible to pass
// another "this" to the method.
public var power:Function = function ():int
{
this.a += 1;
trace(this.a);
return this.a * Wrapper.recall();
}
}
我正在寻找一种方法来做这样的事情:
class ClassA
{
public function func1():void{}
}
class ClassB extends ClassA
{
public override function func1():void{
trace("middleman");
base.func1();
}
}
我知道代理 class,但我想要实现的是
var instance:ClassA = new ClassA();
instance = Modifier.messWith(instance); //returns instance with ClassB functionality, without ClassB being defined at compile time
我想要提供额外功能的 class 数量很高,我不想花所有时间为每个功能编写一个扩展 class。另一个用于不同的功能。有什么方法可以实现我正在尝试的目标吗?
编辑: 作为对答案的回应,这是整个事情的最终目标,因为我对这个问题有些混淆:
我需要一种生成动态代理的方法,类似于 Castle.DynamicProxy 在 C# 中所做的,以便创建我正在处理的远程调用概念库。现有的 Proxy class 完全符合我的要求,但有一个致命的缺点 - 它需要代理 class 来扩展 Proxy,这有两个缺点: 1) 我需要代理的所有 classes 都需要扩展代理,这在使用现有代码时会出现问题。 2) 如果一个对象只是简单地包装在一个代理的通用实现中(一个 class 代理一个随机 calasses 的函数调用并用它们做一些事情),该对象不能传递给具有强类型参数的现有函数,因为它没有正确的类型(代理或其扩展是唯一可能的类型)。
我认为你应该分享它的端点目标,因为你要求的东西对于 AS3 概念来说非常陌生。
尽管如此,但有一定的限制,它是可行的。
实施:
package assortie
{
public class Wrapper
{
// The public interface to wrap methods.
static public function wrap(target:Object, name:String, another:Function):void
{
var aWrapper:Wrapper = new Wrapper;
// Remember the wrapped object:method.
aWrapper.wrapped = target;
aWrapper.wrappee = target[name];
aWrapper.wrouter = another;
// Substitute it with the own method.
target[name] = aWrapper.delegateWrapper;
}
// A stacked list of active wrappers.
static private var list:Array = new Array;
// A wrapper method should call Wrapper.recall(...)
// to invoke the wrapped method.
static public function recall(...args:Array):*
{
var result:*;
var aWrapper:Wrapper = list[list.length - 1];
if (aWrapper)
{
result = aWrapper.wrappee.apply(aWrapper.wrapped, args);
}
return result;
}
private var wrapped:Object;
private var wrappee:Function;
private var wrouter:Function;
private function delegateWrapper(...args:Array):*
{
// Register self as the last activated wrapper.
list.push(this);
var result:*;
result = wrouter.apply(wrapped, args);
// Remove self from the active wrappers' list.
while (list.indexOf(this) > 0)
{
list.splice(list.indexOf(this), 1);
}
return result;
}
}
}
用法:
package assortie
{
import assortie.Wrapper;
import flash.display.Sprite;
public class MixIn extends Sprite
{
public var a:int = 1;
public function MixIn()
{
// See internal class at the bottom.
var aMix:MeexEen = new MeexEen;
// You can stack the wrappers.
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
Wrapper.wrap(this, "power", aMix.power);
trace("The Power of Mixing In:", power());
// Outputs:
// 2
// 3
// 4
// 5
// 6
// The Power of Mixing In: 720
}
// The method to be wrapped should be declared as variable.
// It is not possible to replace a properly declared method.
public var power:Function = function ():int
{
return 1;
}
}
}
import assortie.Wrapper;
// Should be either dynamic or contain the declarations
// of all the variables accessed through "this".
internal dynamic class MeexEen
{
// The wrapping method should be declared as closure.
// Outherwise the method is bound to its original
// instance and it is not possible to pass
// another "this" to the method.
public var power:Function = function ():int
{
this.a += 1;
trace(this.a);
return this.a * Wrapper.recall();
}
}