AS3中的函数重载

时间:2015-05-05 08:08:24

标签: actionscript-3 flash return-value return-type overloading

我刚刚在网上看到as3不支持函数重载。我在网站上看到了与此相关的问题,但答案似乎不足以解决我的问题。

我尝试通过以下方式重载事件类:

public function SelectEvent(type:String, selecteditem:Buyer, bubbles:Boolean=false, cancelable:Boolean=false)
        {
            super(type,bubbles,cancelable);
            selectedbuyer = selecteditem;
        }
        public function SelectEvent(type:String, selecteditem:Shop, bubbles:Boolean=false, cancelable:Boolean=false)
        {
            super(type,bubbles,cancelable);
            selectedshop = selecteditem;
        }

我不知道如何在没有重载的情况下完成这项工作,这与AS3不兼容。

另外,我有一个返回功能:

override public function clone():Event
        {
            return new SelectEvent (type, selecteditem, bubbles, cancelable);
        }

如何针对不同的参数返回不同的项目?如果买方通过,则需要退回买方。如果商店通过,则需要退回商店。此外,买家和商店都是电影剪辑。有没有办法通过将它们称为动画片段来区分它们?

3 个答案:

答案 0 :(得分:1)

你不能在as3中重载函数,但你可以将参数作为Object传递并检查类似的类型:

public function SelectEvent(type:String, selecteditem:Object, bubbles:Boolean=false, cancelable:Boolean=false)
    {
        super(type,bubbles,cancelable);
        if(selecteditem is Shop) {
            selectedshop = selecteditem as Shop
        } else if(selecteditem is Buyer) {
            selectedbuyer = selecteditem as Buyer
        }
    }

答案 1 :(得分:1)

其他答案非常强大且适用于多种编程语言,但这种方法在AS3中也很常见,不需要类型转换:

public class SelectedEvent {
    public static const SELECTED_BUYER:String = "selectedBuyer";
    public static const SELECTED_SELLER:String = "selectedSeller";

    public var buyer:Buyer;
    public var seller:Seller;

    public function SelectEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
    {
        super(type,bubbles,cancelable);
    }
}

//[...]
var evt:SelectedEvent = new SelectedEvent(SelectedEvent.SELECTED_BUYER);
evt.buyer = selectedBuyer;
dispatchEvent(evt);

这种方法的缺点显然是它不能强制您在调度事件之前为属性设置值。我喜欢这种方法,当我有大量的事件,从逻辑上看,它们应该在同一个类下分组,但每个事件需要不同的属性。

或者,如果出于某种原因,无论用户是选择买家还是卖家,您都需要使用相同的事件,您可以像这样处理:

private function selectedEventHandler(event:SelectedEvent):void {
    if (event.buyer) {
         //do stuff here
    } else if (event.seller) {
         //do other stuff here
    }
}

再次避免了对类型转换的需求(尽管你可以说这种方法没有更好)

我认为Adobe会这样做:

public function SelectEvent(type:String, selectedBuyer:Buyer = null, selectedSeller:Seller = null, bubbles:Boolean=false, cancelable:Boolean=false)
    {
        super(type,bubbles,cancelable);
        this.buyer = selectedBuyer;
        this.seller = selectedSeller;
    }
}

但我讨厌凌乱的建设者。

答案 2 :(得分:0)

答案是多态性。

您应该使用两者的超类型,而不是将参数键入BuyerShop

是的,Object是所有内容的超类型,因为每个对象都是Object类型(顾名思义)。 BuyerShop都延伸Object。没有办法绕过它。但是,通过这种方式,您可以将所有内容传递给您的活动。它看起来就像那样。

public class SelectEvent extends Event
{

    private var selectedObject:Object; // I prefer camelCase (new words in the name start with capital letter)

    public function SelectEvent(type:String, selectedItem:Object, bubbles:Boolean=false, cancelable:Boolean=false)
    {
        super(type,bubbles,cancelable);
        selectedObject = selectedItem;
    }

如您所见,此处的目标是使用与您的两种类型兼容的类型。 Object就是这样一种类型,因为你的两种类型都扩展了它。您总是可以传递更专业的类型(也就是您的类型),其中需要较少的专业(即对象)。

使用兼容类型的相同方法的不同解决方案是使用interface

接口基本上只是一个功能列表。它甚至不包括如何实现这些功能。一个简单的例子是驾驶执照。拥有许可证的人可以驾驶汽车,停放汽车等。如果一个班级完成了界面列出的所有内容,它就可以实现该界面。这就像收到驾照一样,因为你已经证明你可以开车,停车等。 只要有什么东西可以在幕后实现这些功能,这并不重要。

鉴于上述定义,自驾车可以获得驾驶执照,即使它不是人类,也不会与人类有太多共同之处。它能够做那些获得驾驶执照所必需的东西。这一切都很重要。

请记住,这个功能列表很可能是空的。 所以让我们创建一个空接口:

package
{
    public interface ISelectable  // start with capital I, then capital first letter of name by convention
    {

    }
}

就像类一样,接口也是类型。在这种情况下,您选择的事件期望的类型:

public class SelectEvent extends Event
{

    private var selected:ISelectable;

    public function SelectEvent(type:String, selectedItem:ISelectable, bubbles:Boolean=false, cancelable:Boolean=false)
    {
        super(type,bubbles,cancelable);
        selected = selectedItem;
    }

要传递BuyerShop,它们必须属于ISelectable类型。因此他们必须实施它:

public class Buyer extends Whatever implements ISelectable

public class Shop extends Whatever implements ISelectable

请注意,超类是什么并不重要。再说一遍:界面不关心继承。

使用界面的重点是什么?当使用较少的代码时,Object几乎完全相同?

关键是界面是明确定义的。如上所述,Object允许您传递所有内容。即使是没有任何意义的事情。

问题是您首先创建该事件的原因。您希望收听该事件,以便在选择某事时收到通知。这就是我从您使用的名称中可以看出的内容。但那又怎样?你想用这些东西做什么?

以下是一个示例场景:每当选择某个内容时,它应该改变它的外观。

您现在可以做的是将这些内容添加到界面:     包     {         public interface ISelectable //以大写字母I开头,然后是按照惯例的首字母大写字母         {             function selected():void;             function deselected():void;         }     }

现在,您的类必须拥有这些方法才能实现接口。每个人对选择的反应都不同。在下面我假设它们都是Sprite个对象,它们在选择或去除后会改变它们的外观。

public class Buyer extends Sprite implements ISelectable
{
    public function selected():void
    {
        alpha = 1; // fully visible
    }
    public function deselected():void
    {
        alpha = .5; // transparent
    }

或者像这样:

public class Shop extends Sprite implements ISelectable
{
    public function selected():void
    {
        x += 10; // move to right a bit
    }
    public function deselected():void
    {
        x -= 10; // move back
    }

不同之处在于界面将保证对象能够做出承诺的事情。当你雇用驾驶执照的人时,他可能是一个人,一个自驾车,一个机器人甚至一只猴子。你不知道它会是什么,但你可以保证无论外星人是什么,它都可以开车,停车等等。

使用Object,您没有这种保证,因为它可能就是一切。

上述界面的用例可能如下所示:

使用此修改后的Event类来检索所选项目和类型常量:

public class SelectEvent extends Event
{
    public const SELECTED:String = "selected";

    private var selected:ISelectable;

    public function SelectEvent(type:String, selectedItem:ISelectable, bubbles:Boolean=false, cancelable:Boolean=false)
    {
        super(type,bubbles,cancelable);
        selected = selectedItem;
    }
    public function get selectedItem():ISelectable
    {
        return selected;
    }

收听该类型的事件:

addEventListener(SelectEvent.SELECTED, onSelected);

function onSelected(event:SelectEvent):void
{
    event.selectedItem.selected();
}