Здравствуйте, ioni, Вы писали:
I>Каждый раз когда я вижу такой switch — case на несколько экранов приходит непреодолимое желание
I>изменить этот код.
I>Что хотелось бы, так это избавиться от такой конструкции, заменив это чем нибудь другим.
I>Вопрос производительности пока не принципиален. Интересны именно подходы.
Зайдите сюда
http://www.dslev.narod.ru/PointersToMembers.htm и прочитайте статью внимательно, может описанный подход Вам поможет. Статья небольшая, в конце статьи написано "Наконец этот подход можно использовать для выполнения любого ряда действий, а не только рисования, фактически можно организовать сценарий из N функций, выполняя их в определенном порядке, который очень просто изменяется."
Здравствуйте, ioni, Вы писали:
I>Мне интересно а как вы решаете проблему большого switch.
Тут много было решений и с макросами и с шаблонами... Но странно, что никто так и не предложил тру-C++ подход. Вобще говоря я так понимаю человека интересует не оптимизации компилятора (врядли обработчик команд является узким местом), а именно дизайн и гибкость кода.
В общем мой вариант без использования шаблонов, макросов, буста и т.п:
class Command
{
public:
virtual ~Command() {}
virtual void Initialize(Parser* context) {}
virtual Command* Clone() const = 0;
virtual void Run() = 0;
};
class SomeCommand : public Command
{
public:
SomeCommand(const SomeCommand &src) {}
void Run()
{
std::cout << "hello";
}
// Эти методы одинаковые для всех комманд
// их можно обернуть в простой макрос.
virtual Command* Clone() const { return new SomeCommand(*this); }
virtual void Initialize(Parser& parser)
{
// Вызываем перегруженный метор void Parser::Parse(SomeCommand& command);
// Он аполняет поля комманды если таковые имеются.
parser.Parse(*this);
}
};
const int MAX_COMMANDS = 1;
Command* commands[MAX_COMMANDS];
void main()
{
Parser parser;
commands[0] = new SomeCommand;
Command* cmd = commands[0]->Clone();
cmd->Initialize(parser);
cmd->Run();
delete cmd;
}
auto_ptr и прочее не испольуется намеренно, т.к. я не в курсе о стратегии управления памятью в коде автора. При желании можно добавить и макросов и шаблонов по вкусу. Тут же только суть.
Объяснение: имеем массив экемпляров комманд. При получении комманды клонируем экземпляр по индексу в массиве. Далее вызываем функцию SomeCommand::Initialize которая передает управление в парсер, где происходит разбор параметров комманды. После разбора мы вольны делать с нею что угодно, например сохранить в очередь на выполнение, ну или как в данном случае просто запускаем методом SomeCommand::Run.
Плюс этого подхода в том, что мы отделяем парсер комманд от действия. Таким образом теперь можно например выполнять обработку комманд в другом потоке, независимом от парсера. Код парсера не загромождается ненужными инклудами, которые необходимы для обработки комманды.
Недостаток: много сопроводительного кода.