Eugeny89
Eugeny89

Reputation: 3731

Command pattern and AS3

Just curious how do you guys solve the problem of encapsulation of commands. Are you creating a separate class for each command? Or there's another way (without huge amount of classes)?

Note that I'm facing the problem on action script 3.

Upd: to be more precise, I want to know how to organize command related machinery (e.g. class for each command).

Thank you in advance!

Upvotes: 4

Views: 1796

Answers (3)

J. Holmes
J. Holmes

Reputation: 18546

The command pattern is all about separating out concerns between three different categories of objects:

  1. The Invoker
  2. The Receiver
  3. The Command

Which, as wvxvw pointed out, usually means that you have a TON of classes that implement ICommand that really just work as proxies to call methods on a Receiver -- which is required for Java. This can get a little unmanageable over time.

But lets look at some code, I'm going to follow the sample code that that introduces the basics of the command pattern found here, but simplified slightly for clarity:

So first the receiver:

// Receiver
public interface IStarShip {
    function engage():void;
    function makeItSo():void;
    function selfDestruct():void;
}

public class Enterprise implements IStarShip {
    public function Enterprise() { }

    public function engage():void {
        trace(this, "Engaging");
    }

    public function makeItSo():void {
        trace(this, "Making it so");
    }

    public function selfDestruct():void {
        trace(this, "Self Destructing");
    }
}

And the invoker:

// invoker
public class CaptPicard {
    private var _command:ICommand;

    public function CaptPicard() { }

    public function set command(cmd:ICommand):void {
        this._command = cmd;
    }

    public function issueCommand():void {

    }
}

And finally some commands:

// command
public interface ICommand {
    function execute():void;
}

public class EngageCommand implements ICommand 
{
    private var receiver:IStarShip

    public function EngageCommand(receiver:IStarShip) {
        this.receiver = receiver;
    }

    public function execute():void {
        receiver.engage();
    }
}

public class SelfDestructCommand implements ICommand 
{
    private var receiver:IStarShip

    public function SelfDestructCommand(receiver:IStarShip) {
        this.receiver = receiver;
    }

    public function execute():void {
        receiver.selfDestruct();
    }
}   

public class MakeItSoCommand implements ICommand 
{
    private var receiver:IStarShip

    public function MakeItSoCommand(receiver:IStarShip) {
        this.receiver = receiver;
    }

    public function execute():void {
        receiver.makeItSo();
    }
}   

And we can hook these up by saying something like:

var enterprise:Enterprise = new Enterprise;
var picard:CaptPicard = new CaptPicard();
picard.command = new SelfDestructCommand(enterprise);
picard.issueCommand();

So far, it follows fairly closely with the example code, and is a pretty standard implementation of the Command Pattern in ActionScript. But, right now we have three ICommand implementations and as the number of things that a reciever can do increase, so does the number of commands that are required to orchestrate the pattern.

And if we start to examine the Command itself, it doesn't really do much other than tell the receiver to do some work. As wvxvw implied, there is already the facility in actionscript to do just that: First-class function.

Lets take a look at possible implementation of that to reduce the number of implementations of ICommand you need to have floating around, without changing your pattern at all.

Lets say that we made a generic type of command, lets say:

public class GenericCommand implements ICommand {

    private var worker:Function;

    public function GenericCommand(worker:Function) {
        this.worker = worker;
    }

    public function execute():void {
        this.worker.call();
    }
}

Notice that our new type still implements ICommand, but instead of being bound directly to some implementation, it accepts a worker to do some work on. It doesn't execute it right away, it just holds on to it and waits for something else to put it in motion.

Then we could switch our code to being something like this:

var enterprise:Enterprise = new Enterprise;
var picard:CaptPicard = new CaptPicard();
picard.command = new GenericCommand(function() { enterprise.selfDestruct(); });
picard.issueCommand();
picard.command = new GenericCommand(function() { enterprise.engage(); });
picard.issueCommand();
picard.command = new GenericCommand(function() { enterprise.makeItSo(); });
picard.issueCommand();

With this one GenericCommand, we could unroll all of our commands into this new pattern (or mix and match between them).

But if you look close, you can see by using this we are tightly coupling a generic command to a IStarShip by referencing the closed-over variable enterprise, and perhaps even more worrying is if we aren't careful we could be creating a ton of these closures. They would all need to be garbage collected at some point, which could effect performance, or worse cause a memory leak.

We could decouple that one layer more and make it even more dynamic. Rather than using closing over directly to the local variable enterprise we could use a factory pattern to help generate our command dynamically on the fly. Consider this:

public class StarShipCommandFactory {
    private var worker:Function;

    public function StarShipCommandFactory(worker:Function) {
        this.worker = worker;
    }

    public function to(receiver:IStarShip):ICommand {
        return new GenericCommand(function() {
            worker.call(undefined, receiver);
        });
    }
}

Then we can use that to create a command factory for creating these commands. Something like:

var enterpriseA:Enterprise = new Enterprise();
var enterpriseB:Enterprise = new Enterprise();
var picard:CaptPicard = new CaptPicard();

var selfDestuctor:StarShipCommandFactory = new StarShipCommandFactory(function(starShip:IStarShip):void {
    starShip.selfDestruct();
} );

var blowUpA:ICommand = selfDestructor.to(enterpriseA);
var blowUpB:ICommand = selfDestructor.to(enterpriseB);

picard.command = blowUpA;
picard.issueCommand();

picard.command = blowUpB;
picard.issueCommand();

This will all reduce the number of static classes that you need to generate in favor of dynamically created objects leveraging the properties first-class functions, but still applying the same general idea.

In fact, with this pattern you can build up very complicated commands that proxy to multiple actions on multiple receivers, which can be a very powerful thing.

Why would you want to use traditional implementations of ICommand then?

One of the biggest reasons to stick with the traditional pattern is ease in serialization. Because the objects are explicit, it makes them very easy to serialize. So, lets say you had a stack of Vector.<ICommand>. You could easily serialize them, write them out, then later, reload them and replay them in order and should be at the exact same state that you were. Dynamically generated objects like the ones I described before a little more tricky to do that with -- not impossible, just trickier.

If you are concerned about maintaining a huge number of ICommands that map to receiver actions, then in the past I have used meta-programming to solve this problem. Use ruby/python to parse a set number of files, and automatically generate the ICommand mappings. They are, a lot of the times, fairly naive implementations, which are prime candidates for automation.


Anyway, those are my thoughts on the subject. There are a lot more things that you could do to help simplify your code -- I have just scratched the surface. Your mileage may vary -- Remember: "Find a pattern that solves your problem, not the other way around" -- but perhaps you can glean some useful information from it.

Upvotes: 8

Gunnar Karlsson
Gunnar Karlsson

Reputation: 28480

I use one class per command. A multitude of classes is a small price to pay for the flexibility the pattern offers for certain problem domains.

Using a game example, with a custom class called GameEntity - player,enemy etc - I'd start by defining a command interface

ICommand{
    function execute():void;
}

Each command class then implements the execute method on a receiver injected into the constructor:

public class GoRight implements ICommand{

    _gameEntity:GameEntity

    public function GoRight(entity:GameEntity){
        _gameEntity = entity;
    }

    public function execute():void{
        _gameEntity.x++;
    }
}

and

public class GoLeft implements ICommand{

    _gameEntity:GameEntity

    public function GoLeft(entity:GameEntity){
        _gameEntity = entity;
    }

    public function execute():void{
        _gameEntity.x--;
    }
}

and so on for every command.

If you use a stack where one command is called after the other finishes you need to add eventlisteners to listen to command completion as a trigger to start the next.

However IMHO if you find yourself building a piece of software where the command pattern becomes a key architectural solution I would think hard about whether actionscript or rather the Flash player is really the right tool. For task queuing and do/undo of long command chains, concurrency - something Flash doesn't offer - becomes important for a good user experience. That's just my opinion of course...

Upvotes: 2

user797257
user797257

Reputation:

Command pattern is a coverup for Java's lack of higher order functions (inability to pass references to functions around). There's no point in using this pattern in AS / other ES languages because this problem doesn't exist there.

It is very unfortunate that academia these days uses Java for CS studies, especially if CS isn't your major. This would explain this and other Java-isms transplanted into other languages w/o any critical analysis.

Upvotes: 9

Related Questions