Re: Поделитесь идеями... :-)
От: alexplev  
Дата: 11.01.10 20:51
Оценка:
Здравствуйте, ioni, Вы писали:


I>Каждый раз когда я вижу такой switch — case на несколько экранов приходит непреодолимое желание

I>изменить этот код.
I>Что хотелось бы, так это избавиться от такой конструкции, заменив это чем нибудь другим.
I>Вопрос производительности пока не принципиален. Интересны именно подходы.

Зайдите сюда http://www.dslev.narod.ru/PointersToMembers.htm и прочитайте статью внимательно, может описанный подход Вам поможет. Статья небольшая, в конце статьи написано "Наконец этот подход можно использовать для выполнения любого ряда действий, а не только рисования, фактически можно организовать сценарий из N функций, выполняя их в определенном порядке, который очень просто изменяется."
Re: Поделитесь идеями... :-)
От: Critical Error ICQ: 123736611
Дата: 19.01.10 23:29
Оценка:
Здравствуйте, 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.

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

Недостаток: много сопроводительного кода.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.