2012-02-26 5 views
1

предположим, что я создаю пользовательскую версию DisplayObject, которая переопределяет некоторые функции, сеттеры и геттеры. Пример:Наследование AS3 и полиморфизм

public class MyDisplayObject extends DisplayObject{ 
    .... 
    override public function get x():Number{ 
     return 123; 
    } 
    .... 
} 

и теперь я хочу, чтобы создать класс MyMovieClip, который, как предполагается, так же, как MovieClip, только с той разницей, что он наследует от MyDisplayObject вместо DisplayObject. Есть ли какой-либо простой способ сделать это без необходимости перекодировать всю реализацию MovieClip (что практически невозможно)?

+5

Возможно, вам лучше построить свой класс через композицию, чем наследование. Извините, не так много ответа, поэтому я просто помещаю его в комментарии. –

ответ

1

Существует методика подделки множественного наследования в ActionScript 3 как outlined here. В основном это касается импорта внешнего AS-файла непосредственно в другой класс. Это не красиво или элегантно, но для всех целей и целей это потенциальное решение.

Конечно, интерфейс не может расширить другой класс, так что вам нужно будет взять свой собственный код из MyDisplayObject, место, что в отдельном интерфейсе (возможно, под названием MyInterface?), А затем реализовать его в обоих MyDisplayObject (простирающийся от DisplayObject) и MyMovieClip (от MovieClip), используя технику, описанную на веб-сайте выше.

3

В ActionScript фактического множественного наследования нет. Но если вы можете жить с пониженной производительностью, вы можете расширить класс Proxy, чтобы имитировать его.

В вашем случае вы должны создать класс, который расширяет Proxy, который содержит экземпляр объекта любого типа и передает его через конструктор: все вызовы свойств перенаправляются на этот экземпляр, за исключением вызовов в 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. Создайте свою «лишнюю» функцию в параллельной серии классов
  2. Создать свой фактический обычай DisplayObject, MovieClip и т.д. классы наследуют (IS-A) непосредственно из соответствующих встроенных в классах Flash, но также и HAVE-A ()) экземпляр соответствующего класса расширения. Чтобы добавить или переопределить элементы в пользовательском классе, вы просто кладете однострочную оболочку в класс расширения.

Я уверен, что иллюстрация была бы более полезной, так что вот она. Обратите внимание, что мои классы расширения наследуют друг от друга (поэтому мне не нужно переписывать материал, который я хочу применить по всей цепочке), но «используемые» классы наследуются от классов 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); 
     } 
    } 
} 
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]); 
    } 

} 

Это позволит вам учитывать разные типы подобных объектов, предоставляя различные наборы методов для каждого класса. Это несколько менее строгое в плане ввода - потому что вы «теряете» тип сигнатуры функции - вы, однако, будете уведомлены во время выполнения, если типы не совпадают. Ну, это компромисс.

Другой недостаток - вы не сможете «прокрасться» в экземпляры этого класса на месте, где требуются определенные предопределенные типы, даже если вы реализуете требуемые методы. Тем не менее, несколько раз это жизнеспособные решения, если количество различных видов объектов возможно велико или не может быть предсказано во время написания кода.

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; 
    } 
    .... 
} 
Смежные вопросы