嵌套函数?

时间:2012-08-04 00:10:21

标签: actionscript-3

我没有在其中一个函数(例如,一行)中设计很多只有少量不同的类,而是根据构造函数参数更改了函数。像这样:

public class SomeClass {
    public var toDo : Function;

    public SomeClass1( option: Boolean){
        if (option){
            function function1():void{
                // something here;
            }
            toDo = function1;

        } else{
            function function2():void{
                // something here;
            }
            toDo = function2;
        }
    }
}

这是好习惯吗?或者,我可以将它分成一个基类和2个子类,但是当它们相差很小时,将它们作为具有2个不同函数的两个不同类似乎是浪费。或者我可以存储选项并在函数中使用if语句,但是每次运行函数时我都要检查它,每次都是相同的。什么是最好的事情?

2 个答案:

答案 0 :(得分:3)

您的方法没有任何本质上的错误 - 这是一种完全有效的方法 - 只要您完全了解自己在做什么,以及一些注意事项。

重复的功能

在执行此方法时,我最关心的一个问题是每次启动此类的实例时,您都在创建一个新函数。制作1000个实例,你有1000个函数浮动。作为方法,只有一个引用实例在稳定的上下文中被激活。

解决此问题的一种可能方法是在构造函数之外使用静态函数定义:

public class SomeClass {
    public var toDo:Function; 

    private static var doIt1:Function = function():void { };
    private static var doIt2:Function = function():void { };

    public function SomeClass(options:Boolean) {
        this.toDo = (option) ? doIt1 : doIt2;
    }
}

或者,您可以使用对实例方法的引用而不是函数:

public class SomeClass {
    public var toDo:Function; 

    private function doIt1():void { };
    private function doIt2():void { };

    public function SomeClass(options:Boolean) {
        this.toDo = (option) ? doIt1 : doIt2;
    }
}

请参阅下一节,以便更好地区分这两种方法。

无论哪种方式,这只会分配一个函数,无论你有多少个这个类的实例。

绑定与未绑定功能

方法函数之间的ActionScript有一个微妙之处。虽然相似,但它们的工作方式并不相同。 bound method是从实例中提取的方法。在执行这些方法时,this将始终指向它们来自的实例。

请考虑以下代码:

public class SomeClass {

    private var number:Number;

    public function SomeClass(val:Number):void {
        number = val;
    }

    public var doIt:Function;

    public var getNumberUnbound:Function = function():Number {
        return this.number;
    }

    public function getNumberBound():Number {
        return this.number;
    }
}

非常简单的例子,构造函数接受Number然后有一个方法返回该值,一个函数也返回该值,然后是一个名为doIt的公共函数,当前未分配。首先让我们考虑一下:

var instance1:SomeClass = new SomeClass(1);
instance1.getNumberBound(); // 1
instance1.getNumberUnbound(); // 1

这会像我们对两个调用所期望的那样返回1。但现在,让我们试着变得棘手并使用.call() - 或.apply()

var instance1:SomeClass = new SomeClass(1);
var instance2:SomeClass = new SomeClass(2);
instance1.getNumberBound.call(instance2); // 1
instance1.getNumberUnbound.call(instance2); // 2

注意这次我们得到不同的版本。绑定调用仍然返回1,因为它仍然卡住instance1,其中未绑定的调用返回2,因为它在它认为的任何上下文中执行应该在。事实上,考虑一下:

instance1.getNumberBound.call(null); // 1;
instance1.getNumberUnbound.call(null); // ERROR!

在这种情况下,getNumberBound仍在instance1的上下文中执行,但未绑定的函数失败,因为this现在等于null,{{1显然没有任何意义。

现在让我们更加奇怪:

null.number

在这里,您可以看到,无论您尝试从var instance1:SomeClass = new SomeClass(1); var instance2:SomeClass = new SomeClass(2); instance2.doIt = instance1.getNumberBound; instance2.doIt(); // 1 instance2.doIt = instance1.getNumberUnbound instance2.doIt(); // 2 分离getNumberBound,您都无法做到。即使我们已将方法的引用推送到instance1,它仍然在instance2的范围内执行。

这就是我的意思,当我说instance1可能不是你所期望的那样。根据其绑定或未绑定,或者如果调用者使用this.call()明确更改此内容,.apply()可能会与您预期的情况大相径庭。

我的直觉

我会使用occam的剃刀,这对我来说是存储选项并在一个名为this的方法中进行切换。即使你把这个函数称为吨,单个条件语句的成本也是可以忽略不计的,我会等待分析器告诉我在尝试找出解决任何性能问题的更好方法之前花了太长时间。可能性,您的性能问题将存在于其他地方。

那就是说,我确实使用了这种模式。实际上,您可以将您的工作人员注入您的实例,并一起避免这种情况。

toDo

了解ActionScript中的函数式编程概念,一旦掌握了它,就可以成为一个非常强大的东西。我不会避免它,但我会谨慎使用它。与最强大的东西一样,如果操作不正确,可能会非常危险。

继承可能有效,但尽量不要落入“继承是一切的解决方案”。继承只应该真正尝试模拟“是一种”关系,。组合可能在结构上更好,但也可以为功能方法提出论据。

答案 1 :(得分:1)

在考虑代码时,我会问两个问题:

  • 阅读有多容易?
  • 延伸有多容易?

我发现我通常会依赖于类继承。我觉得调试很简单,而且(大部分)简单地扩展。如果存在将标志(如willProcessConfirmKey)更改为方法或单独的子结构的问题,则它很简单(即使需要进行大量测试)。将很多类折叠回较小的类组也很简单。

从您的评论中,我认为可能会设置如下:

import flash.display.Sprite;
import flash.events.KeyboardEvent;

public class Menu extends Sprite
{
    protected var keys:Array;
    protected var _willProcessConfirmKey:Boolean;

    public function Menu(willProcessConfirmKey:Boolean)
    {
        super();

        this.willProcessConfirmKey = willProcessConfirmKey;

        addEventListener(KeyboardEvent.KEY_DOWN, keyHnd, false, 0, true);
    }

    private function keyHnd(e:KeyboardEvent):void
    {
        storeKeys();
        processKeys();
    }

    private function storeKeys():void
    {
        // store keys in some fashion here
    }

    protected function processKeys():void
    {
        // this function is provided for overriding.
    }

    public function get willProcessConfirmKey():Boolean 
    {
        return _willProcessConfirmKey;
    }

    public function set willProcessConfirmKey(value:Boolean):void 
    {
        _willProcessConfirmKey = value;
    }
}

public class Menu1Level extends Menu
{
    public function Menu1Level(willProcessConfirmKey:Boolean)
    {
        super(willProcessConfirmKey);
    }

    override protected function processKeys():void
    {
        super.processKeys();

        // handle movement and selection of items here.
        if (willProcessConfirmKey) {
            // process confirms
        } else {
            // skip processing confirms.
        }
    }
}

public class Menu2Level extends Menu
{
    public function Menu2Level(willProcessConfirmKey:Boolean)
    {
        super(willProcessConfirmKey);
    }

    override protected function processKeys():void
    {
        super.processKeys();

        // handle movement and selection of items here.
        if (willProcessConfirmKey) {
            // process confirms
        } else {
            // skip processing confirms.
        }
    }
}

并像这样使用:

public var menu1Level_NoConfirm:Menu1Level = new Menu1Level(false);
public var menu2Level_Confirm:Menu2Level = new Menu2Level(true);

如果您发现willProcessConfirmKey标记作为单独的类更好,那么您可以扩展Menu1LevelMenu2Level,并重新编码Menu以适应。

所有这一切都说,我最初会想到找一个免费的菜单系统,甚至付一个。正确编程是一个很大的痛苦。由于Actionscript与Javascript密切相关,您可能会发现可以将JS菜单系统直接移植到AS3中。

修改

(更正了声明示例中的错误。)