повысить диаграмму состояния передачи аргументов с переходом - PullRequest
3 голосов
/ 06 августа 2011

Я пытаюсь изучить boost :: statechart.

Я хочу создать небольшое приложение, которое загружает файл.

//  --------------------------------
// |                                |
// |           O     Project        |
// |           |                    |
// |           v                    |
// |  ----------------------------  |
// | |                            | |
// | |         Unloaded           | |
// |  ----------------------------  |
// |  |              ^              |
// |  | EvLoad       | EvUnload     |<-----O
// |  v              |              |
// |  ----------------------------  |
// | |                            | |
// | |         Loaded             | |
// |  ----------------------------  |
// |           |   ^                |
// |           |   | EvLoad         |
// |           -----                |
//  --------------------------------

Но как мне перенести аргументы в состояние?Например, имя файла?Если я сохраню имя файла внутри EvLoad, я смогу легко получить к нему доступ для реакции в состоянии

struct Loaded : sc::simple_state< Loaded, Project>
{
    typedef sc::custom_reaction< EvLoad > reactions;
    sc::result react( const EvLoad & e )
    {
        //load file e.path()
        ...
        return discard_event();
    }
}

Но когда я в состоянии Unloaded, я вызываю конструктор Loaded и не могу пройтиаргументы этому.Единственный обходной путь, к которому я пришел, - это перепостить событие перед выполнением перехода, но мне это кажется немного грязным.

struct Unloaded : sc::simple_state< Unloaded, Project >
{
    typedef sc::custom_reaction< EvLoad > reactions;
     sc::result react( const EvLoad & e )
     {
         post_event( e ); //workaround to pass the event to the loaded state
         return transit<Loaded>();
     }
};

Есть ли лучшая альтернатива?

Ответы [ 2 ]

9 голосов
/ 30 марта 2012

Мы используем метод triggering_event, чтобы получить событие запуска, а затем просто присоединить данные в качестве переменных-членов к событию запуска. Это экономит много усилий при программировании и избавляет нас от необходимости генерировать пользовательские реакции или присоединять переменные перехода к диаграмме состояний (два общих подхода, которые я видел).

4 голосов
/ 07 августа 2011

Я нашел эту ссылку во время поиска в Google после того, как набрал свое предложение ниже, в котором говорится, что то, что вы уже делаете (публикуете внутреннее событие или публикуете событие с данными), является способ сделать это. И это от автора Boost Statechart, так кто же будет спорить? :)

Мое альтернативное предложение заключается в том, что если какие-либо ваши данные существуют на уровне «Проект» после загрузки, тогда загружаемое имя файла будет частью информации о состоянии FSM, на уровне «Проект», а не «Загружен». "состояние.

Вы можете сделать имя файла параметром события / конструктора EvLoad, выполняя пользовательское действие при переходе и сохраняя имя файла, которое загружается в контексте «Проект». Я думаю, что это лучше подходит для концепций диаграммы состояний.

Итак, что-то вроде этого (хотя я не проверял это), и, очевидно, вы бы очистили его, чтобы лучше инкапсулировать членов:

struct EvLoad: sc::event<EvLoad>
{
    std::string filename;

    EvLoad(const std::string& fn) : filename(fn) {}
};

struct EvUnload: sc::event<EvUnload>

struct Project : sc::state_machine<Project, Unloaded>
{
    std::string filename;

    void LoadFile(const EvLoad& e)
    {
        // Load file
        filename = e.filename;
    }

    void UnloadFile(const EvUnload& e)
    {
        filename.clear();
        // Unload file data
    }
};

struct Unloaded : sc::simple_state<Unloaded, Project>
{
    typedef sc::transition<EvLoad, Loaded, Project, &Project::LoadFile> reactions; 
};

struct Loaded : sc::simple_state<Loaded, Project>
{
    typdef mpl::list<
        sc::transition<EvLoad, Loaded, Project, &Project::LoadFile>,
        sc::transition<EvUnload, Unloaded>
    > reactions;
};

Когда вы собираетесь загрузить файловый диск, машина состояний с помощью вызова, такого как project.process_event (EvLoad (filename));

В качестве альтернативы вы можете просто сохранить имя файла в состоянии «Проект» и получить к нему доступ через context (). Filename из состояния Loaded.

...