AS3 中的函数重载

Function Overloading in AS3

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

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

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 不兼容。

另外,我有一个 returning 函数 :

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

如何 return 不同的参数对应不同的项目?如果买方通过,买方需要 returned。如果通过了 Shop,则需要对 shop 进行 returned。此外,买家和商店都是电影剪辑。有没有办法通过将它们称为电影剪辑然后区分它们来做到这一点?

您不能在 as3 中重载函数,但您可以将参数作为对象传递并检查类型:

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
        }
    }

答案是多态。

不要将参数键入 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

接口基本上只是功能列表。它甚至不包括如何实现这些功能。一个简单的例子是驾驶执照。有驾照的人可以开车、停车等。如果 class 执行接口列出的所有操作,它就可以实现该接口。这就像获得驾驶执照一样,因为你已经证明你可以开车、停车等。 什么类型的对象在幕后实现这些功能并不重要,只要有东西就可以。

根据上面的定义,自动驾驶汽车可以获得驾驶执照,即使它不是人类并且与人类没有太多共同之处。它能够完成获得驾驶执照所必需的那些事情。这就是最重要的。

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

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

    }
}

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

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

请注意,super class 是什么并不重要。再次声明:接口不关心继承。


当 Object 用更少的代码完成几乎相同的事情时,使用接口有什么意义?

重点是接口定义明确。如前所述,Object 允许您传递所有内容。即使是没有任何意义的事情。

问题是您首先创建该事件的原因。您想要监听该事件,以便在 某事 被 select 编辑时收到通知。这就是我可以从您使用的名称中看出的。但是然后呢?你想用那些 selected 的东西做什么?

这是一个示例场景:无论什么时候 selected,它都应该改变它的外观。

您现在可以做的是将这些东西添加到界面中: 包裹 { public interface ISelectable // 以大写 I 开头,然后按照约定大写名字的首字母 { 函数 selected():void; 函数 deselected():void; } }

现在您的 class 和 都必须 具有这些方法才能实现接口。每个人对 selected 的反应都不同。在下文中,我假设它们都是 Sprite 对象,在 selected 或取消选择时会改变它们的外观。

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
    }

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

对于一个对象,你没有那个保证,因为它可能是一切。

上述接口的用例可能如下所示:

使用此修改后的事件 class 检索 selected 项目和类型常量:

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();
}

其他答案很可靠,适用于多种编程语言,但这种方法在 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);

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

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

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

这再次避免了类型转换的需要(尽管您可能会争辩说这种方法并没有更好)

我认为 Adob​​e 是这样做的:

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;
    }
}

但我讨厌凌乱的构造函数。