假设我创建了一些自定义版本的DisplayObject,它覆盖了一些函数,setter和getter。例如:
public class MyDisplayObject extends DisplayObject{
....
override public function get x():Number{
return 123;
}
....
}
现在我想生成类MyMovieClip,它应该与MovieClip相同,只是它与MyDisplayObject而不是DisplayObject继承的区别。 有没有简单的方法可以做到这一点而无需重新编写MovieClip的整个实现(这实际上是不可能的)?
答案 0 :(得分:3)
ActionScript中没有实际的多重继承。但是如果你可以忍受降低的性能,你可以扩展Proxy
类来模拟它。
在您的情况下,您将创建一个扩展Proxy
的类,它包含任何类型的Object实例,并通过构造函数传递类型:对属性的所有调用都转发到该实例,除了拨打x
:
package
{
import flash.display.MovieClip;
import flash.utils.Proxy;
import flash.utils.flash_proxy;
public dynamic class MyMovieClip extends Proxy
{
private var mc:*;
private function get differentX():Number {
return 123;
}
private function set differentX( x:Number ):void {
trace( "value received:"+x );
}
override flash_proxy function getProperty( name:* ):* {
if(name == "x") return differentX;
else return mc[name];
}
override flash_proxy function setProperty( name:*, value:* ):void {
if(name == "x") differentX = value;
else mc[name] = value;
}
public function MyMovieClip (clazz:Class = MovieClip) {
if (clazz) mc = new clazz();
}
}
}
用法:
var mc : MyMovieClip = new MyMovieClip( Sprite );
mc.x = 1000; // traces "value received:1000"
trace ("value returned:" + mc.x); // 123;
显然,这种方法仅限于在代理上调用的方法 - 例如,您无法将代理添加到显示列表中。
如果您愿意真正了解这一点,您可能还想查看as3commons bytecode library,它允许您在运行时操作AVM2使用的实际字节代码。您可以aspect-oriented programming将其用于generating dynamic proxies。
答案 1 :(得分:1)
有一种技术可以将ActionScript 3中的多重继承伪造为outlined here。它主要涉及将外部AS文件直接导入另一个类。它既不漂亮也不优雅,但无论出于何种意图和目的,它都是一种潜在的解决方案。
当然,接口不能扩展另一个类,所以你需要从MyDisplayObject中取出自定义代码,将它放在一个单独的接口(可能称为MyInterface?)中,然后将它实现到 MyDisplayObject (从DisplayObject扩展)和 MyMovieClip (从MovieClip扩展)使用上面网站上描述的技术。
答案 2 :(得分:1)
我建议你使用组合和继承的组合。简而言之:
我确信插图会更有帮助,所以在这里。请注意,我的扩展类相互继承(因此我不必重写我希望在链中应用的东西),但“可用”类继承自Flash类。然后,将几行包装器代码复制并粘贴到每个可用类中非常容易:
// Base EXTENSION class. Doesn't inherit from anything
package {
import flash.display.DisplayObject;
public class DisplayObjectExtensions {
private var _displayObject:DisplayObject;
public function DisplayObjectExtensions(displayObject:DisplayObject){
_displayObject = displayObject;
}
// Change the y property to be distance from bottom of stage
public function get y():Number {
return _displayObject.stage.stageHeight - _displayObject.y;
}
public function set y(value:Number):void {
_displayObject.y = _displayObject.stage.stageHeight - value;
}
// A brand new property
private var _customProperty:String;
public function get customProperty():String { return _customProperty; }
public function set customProperty(value:String):void { _customProperty = value; }
}
}
// MovieClip EXTENSION class. Inherits from base EXTENSION class:
package {
import flash.display.MovieClip;
public class MovieClipExtensions extends DisplayObjectExtensions {
private var _movieClip:MovieClip;
public function MovieClipExtensions(movieClip:MovieClip) {
super(movieClip);
_movieClip = movieClip;
}
// Adding custom logic to the gotoAndPlay method
function gotoAndPlay(frame:Object, scene:String = null):void {
trace("Skipping to frame " + frame +
" in movie clip with customProperty = " + super.customProperty);
_movieClip.gotoAndPlay(frame, scene);
}
}
}
// Useable DisplayObject class: Inherits from flash DisplayObject, has wrappers
// for extended functionality contained in EXTENSION class.
package {
import flash.display.DisplayObject;
public class MyDisplayObject extends DisplayObject {
private var _extensions:DisplayObjectExtensions;
public function MyDisplayObject() {
_extensions = new DisplayObjectExtensions(this);
}
public override function get y():Number { return _extensions.y; }
public override function set y(value:Number) { _extensions.y = value; };
public function get customProperty():String { return _extensions.customProperty; }
public function set customProperty(value:String):void { _extensions.customProperty = value; }
}
}
// Useable MovieClip class: Inherits from Flash MovieClip, only needs
// to duplicate wrapper stubs to "inherit" all the custom extensions.
package {
import flash.display.MovieClip;
public class MyMovieClip extends MovieClip {
private var _extensions:MovieClipExtensions;
public function MyMovieClip() {
_extensions = new MovieClipExtensions(this);
}
// Copy and paste wrappers from MyDisplayObject
public override function get y():Number { return _extensions.y; }
public override function set y(value:Number) { _extensions.y = value; };
public function get customProperty():String { return _extensions.customProperty; }
public function set customProperty(value:String):void { _extensions.customProperty = value; }
// Plus the MovieClip-specific override:
public override function gotoAndPlay(frame:Object, scene:String = null):void {
_extensions.gotoAndPlay(object, scene);
}
}
}
答案 3 :(得分:0)
使用DisplayObject的示例过于复杂,因为它涉及处理AS3中的一些不规则事物。 DisplayObject是一个抽象类,你无法在AS3代码中扩展,最接近的是Sprite。
关于扩展,特别是扩展显示对象,我讨厌听起来像一个刺,但我还是会问你这个问题:你确定你真的想要吗?这样有很多麻烦。通过从具有100多种方法的类继承,您可以创建一个可能过于臃肿的类,并且您不太可能完全控制甚至理解该行为。这虽然在AS3中是常见的事情(历史上),但在开发和维护方面会花费很多。如前所述,考虑使用组合,或专注于您的MovieClip版本与内置版本之间的某些方面或差异的实用方法。
然而,一般来说,可能还有另一种方法,它与构图非常相似,但并不完全相同。您可以将其视为“装饰者”,但它并不完全相同。这个想法是你有一个类,它不包含方法的实现,相反,它期望在运行时提供实现。请考虑以下示例:
public class ClassWithDecorator
{
public function ClassWithDecorator(decorator:Vector.<Function>)
{
super();
this._decorator = decorator;
}
public function classMethod(integer:int, string:String):Boolean
{
return this._decorator[0].apply(this, [integer, string]);
}
}
这将允许您通过为每个类提供不同的方法集来计算不同类型的相似对象。这在键入方面稍微不那么严格 - 因为你“松散”了函数签名的类型 - 但是,如果类型不匹配,你将在运行时得到通知。嗯,这是一个权衡。
另一个缺点 - 即使您实现了所需的方法,您也无法“潜入”此类的实例,其中需要一些预定义的类型。如果不同类型的对象的数量可能很大,或者在编写代码时无法预测,有时候这是一个可行的解决方案。
答案 4 :(得分:0)
Movieclip继承自DisplayObject
所以你真正需要做的就是扩展MovieClip,你将继承DisplayObject类中的所有方法。
如果你没有使用任何框架方法,我还建议使用Sprite而不是MovieClip。
MovieClip->Sprite->DisplayObjectContainer->InteractiveObject->DisplayObject->EventDispatcher->Object
public class MyDisplayObject extends MovieClip{
....
override public function get x():Number{
return 123;
}
....
}