你的方法本质上没有任何问题——这是一种完全有效的方法——只要你准确地理解你在做什么,以及一些警告是什么。
重复的功能
使用这种方法时,我最大的担忧之一是每次新建此类的实例时,都会创建一个新函数。制作 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 中,方法和函数之间存在细微差别。虽然相似,但它们的工作方式并不完全相同。绑定方法是从实例中提取的方法。在执行这些方法时,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!
在这种情况下,againgetNumberBound
仍然在 的上下文中执行instance1
,但是未绑定的函数失败了,因为this
现在等于null
,并且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()
or显式更改它.apply()
,this
可能与您预期的完全不同。
我的本能
我会使用 occam 的剃须刀,它对我来说是存储选项并在名为toDo
. 即使您大量调用此函数,单个条件语句的成本也可以忽略不计,我会等待分析器告诉我在尝试找出解决任何性能问题的更好方法之前花费了太长时间。奇怪的是,您的性能问题将在其他地方。
也就是说,当它有意义时,我确实使用了这种模式。事实上,您可以将您的工作人员注入您的实例,并一起避免这种情况。
public class SomeClass {
public var toDo:Function;
public SomeClass(doIt:Function) {
toDo = doIt;
}
}
了解 ActionScript 中的函数式编程概念可能是一件非常强大的事情,一旦您掌握了窍门。我不会避免它,但我会小心使用它。与大多数强大的东西一样,如果使用不当,可能会非常危险。
继承可能有用,但尽量不要陷入“继承是解决一切的办法”。继承应该只真正尝试建模“是”关系,. 组合可能在结构上更好,但也可以为功能方法提出论据。