There is nothing inherently wrong with your approach – it is a totally valid approach – as long as you understand exactly what you are doing, and what some of caveats are.
Duplicated functions
One of the largest concerns for me when doing this approach is that every time you new up an instance of this class, you are creating a new function. Make 1000 instances, you have 1000 functions floating around. Where as methods, there is only one reference instance that gets exectued in a stable context.
A possible way to address this is to use a static function definition, outside of the constructor:
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;
}
}
Or, you could use references to instance methods rather than functions:
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;
}
}
See the next section for a better distinction between these two approaches.
Either way though, this will only allocate a single function, no matter how many instances you have of this class.
Bound vs. Unbound functions
There is a subtlety in ActionScript between methods and functions. Although similar, they don't work quite the same way. A bound method is a method that has been extracted from an instance. While executing these methods, this will always point at the instance that they came from.
Consider the following code:
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;
}
}
Pretty simple example, the constructor takes a Number and then there is one method that returns that value and one function that also returns that value, and then a public function called doIt that is currently unassigned. So first lets consider this:
var instance1:SomeClass = new SomeClass(1);
instance1.getNumberBound(); // 1
instance1.getNumberUnbound(); // 1
This returns 1 as we would expect for both calls. But now, lets try to get tricky and play around with .call() – or .apply().
var instance1:SomeClass = new SomeClass(1);
var instance2:SomeClass = new SomeClass(2);
instance1.getNumberBound.call(instance2); // 1
instance1.getNumberUnbound.call(instance2); // 2
Notice this time we get different resules. the bound call still returns 1 because its still stuck to instance1, where as the unbound call returns 2, cause it is executed in whatever context it thinks it should be in. In fact, consider this:
instance1.getNumberBound.call(null); // 1;
instance1.getNumberUnbound.call(null); // ERROR!
In this case, again getNumberBound is still executed in the context of instance1, however the unbound function fails, because this now equals null, and null.number obviously doesn't make any sense.
Now lets get even weirder:
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
Here you can see that no matter what you try to do to detach getNumberBound from instance1, you just can't do it. Even though we have shoved a reference to a method into instance2, its still executed within the scope of instance1.
So that is what I mean, when I say this might not be what you expect it to be. Depending on if its bound or unbound, or if the caller explicitly changes this using .call() or .apply(), this can be something wildly different than you expect.
My Instinct
I would use occam's razor, which to me is storing option and doing your switch in a method called toDo. Even if you are calling this function a ton, the cost of a single conditional statement is neglible, and I would wait for the profiler to tell me that it was taking too long before trying to figure out a better way to address any performance problem. Odds are, your performance problems will lie elsewhere.
That said, I do use this pattern, when it make sense. In fact, you can just inject your worker into your instance, and avoid the condition all together.
public class SomeClass {
public var toDo:Function;
public SomeClass(doIt:Function) {
toDo = doIt;
}
}
Understanding functional programming concepts in ActionScript can be a very powerful thing, once you get the hang of it. I wouldn't avoid it, but I would use it with care. As with most powerful things, it can be very dangerous if wielded incorrectly.
Inheritance might work, but try not to fall into the "Inheritance is the solution to everything". Inheritance should only really try to model a "is a" relationship, . Composition might be structurally better, but one could make the argument for a functional approach as well.
thismight not be what you are expecting it to be.