Какой шаблон проектирования / RTTI - PullRequest
0 голосов
/ 15 декабря 2009

Я ищу лучший способ отправить объекты в правильный "целевой" объект.

У меня есть базовый класс команд: Cmd, два подкласса: BufferCmd и StateCmd. Команда «GotoLine» является производной от BufferCmd, а «ChangeCmd» является производной от StateCmd. BufferCmds предназначены для перехода к классу Buffer, а StateCmds предназначены для перехода к объекту State.

В настоящее время у меня настроен шаблон Visitor, так что я могу сделать что-то вроде:

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);

Я хочу использовать шаблон «Посетитель», потому что я хотел бы иметь возможность сделать что-то вроде:

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

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

К сожалению, чтобы использовать это, мне нужно знать, на какой объект отправлять команду. Я хотел бы иметь возможность сделать что-то вроде этого:

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);
}

Существует ли шаблон, который наиболее подходит для такого типа ситуаций? Должен ли я даже использовать шаблон Visitor? Очевидно, я хочу избежать этого:

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

Спасибо

1 Ответ

3 голосов
/ 15 декабря 2009

Звучит так, как вы хотите с точно названным шаблоном команды .

Ключ должен переместить отличающиеся параметры accept() в конструктор каждого класса, полученного из Cmd. Например, конструктор GotoLineCommand будет принимать строку и объекты буфера в качестве параметров своего конструктора и хранить указатель или ссылку на объект буфера.

Как только вы это сделаете, вам больше не нужны параметры для accept(), и интерфейс будет одинаковым для всех классов, полученных из 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_;
};
...