views:

174

answers:

1

I'm looking for the best way to dispatch objects to the correct "target" object.

I have a base command class: Cmd, two sub-classes: BufferCmd and StateCmd. Command "GotoLine" is derived from BufferCmd and "ChangeCmd" is derived from StateCmd. BufferCmds are intended to go to a Buffer class and StateCmds are intended to go to a State object.

I currently have a Visitor pattern set up so that I can do something like:

Buffer buffer;
State state;

Cmd *c;
GotoLineCmd gotoCmd = new GotoLineCmd (15);
ChangeCmd changeCmd = new ChangeCommand (...)

c = &gotoCmd;
c->accept (buffer);
c = &changeCmd;
c->accept (state);

I want to use the Visitor pattern because I'd like to be able to do something roughly like:

Cmd *cmds [5];
cmds [0] = new GotoLineCmd (...); 
cmds [1] = new CopyLineCmd (...); 
cmds [2] = new PasteCmd (...); 

foreach (Cmd *c in cmds) {
    c->accept (buffer);
}

Unfortunately in order to use this I need do know what object to send the command to. I'd like to be able to do something like this:

Derive Buffer from Commandable
Derive State from Commandable

Commandables *commandables [1] = {new Buffer (), new State () };

// Then have the foreach type statement look like:
foreach (Cmd *c in cmds) {
    c->accept (commandables);
}

Is there a pattern that is most appropriate for this type of situation? Should I even be using the Visitor pattern? Obvious I want to avoid this:

foreach (Cmd *c in cmds) {
    foreach (Commandable *cmdAbles in commandables) {
        if (c->accept (commandables)) {
              // Okay command accepted... 
              break;
        }
    }
}

Thanks

+2  A: 

Sounds more like you want the aptly-named Command pattern.

The key is to move the differing parameters of accept() into the constructor of each class derived from Cmd. For example, GotoLineCommand's constructor would take the line and the buffer objects as parameters to its constructor, and it would store a pointer or reference to the buffer object.

Once you've done that, you no longer need the parameters to accept() and the interface is the same across all classes derived from Cmd

class Buffer
{
   public:
      void gotoLine(int line);
};

class Cmd
{
   public:
      virtual void accept() = 0;
};

class GotoLineCommand: public Cmd
{
   public:
      GotoLineCommand(Buffer & buffer, int line) :
         buffer_(buffer),
         line_(line)
      {
      }

      virtual void accept()
      {
         buffer_.gotoLine(line_);
      }

   private:
      Buffer & buffer_;
      int line_;
};
Nick Meyer