Фактически, по следам вчерашней темы. Понравилось мне сокращать многословность :) Теперь боюсь, что не смогу вовремя остановится ;)
Вот, например. Один из краеугольных камней в SObjectizer -- это наличие явно выраженных состояний агентов. Причем не только в SObjectizer, в libcaf/libcppa состояния тоже есть, но называются они там behavior. Что не удивительно, т.к. и в SO, и в CAF, агенты представляют из себя конечные автоматы, а какие же КА без состояний? :)
Так вот, до вчерашнего дня смена состояния агента выполнялась методом so_change_state()
virtual void so_define_agent() override { so_change_state( st_free ); so_subscribe( so_direct_mbox() ).in( st_free ) .event( [this]( const msg_take & evt ) { so_change_state( st_taken ); evt.m_who->deliver_signal< msg_taken >(); } ); |
Очень долгое время такой вариант казался нормальным, хотя иногда проскакивала мысль, что state.activate() выглядит получше. В конце-концов попробовал, вроде действительно получше:
virtual void so_define_agent() override { st_free.activate(); st_free.handle( [this]( const msg_take & evt ) { st_taken.activate(); so_5::send< msg_taken >( evt.m_who ); } ); |
Но ведь и это не предел. А что, если задействовать переопределение операторов. Например:
virtual void so_define_agent() override { this >> st_free; st_free.handle( [this]( const msg_take & evt ) { this >> st_taken; so_5::send< msg_taken >( evt.m_who ); } ); |
У меня, конечно, извращенные представления о прекрасном, но мне кажется, что запись this >> st_free более явно говорит о переходе агента в состояние st_free, чем st_free.activate().
Соответственно, интересует мнение читателей: есть ли смысл делать this >> st_free вместо st_free.activate()? Или это, напротив, будет шагом к превращению программы в криптограмму?
Следующий момент связан с тем, что давно привычная цепочка подписки посредством so_subscribe().in().event() позволяла определить один обработчик события для нескольких состояний сразу (что удобно, если реакция на сообщение/сигнал в этих состояниях одинаковая):
so_subscribe( mbox ) .in( st_waiting_connection_result ) .in( st_waiting_auth_result ) .in( st_waiting_reconnection ) .in( st_closing_session ) .event( so_5::signal< msg_shutdown >, &connection_handler::evt_shutdown ); |
Теперь для подписки можно использовать метод state_t::handle, но он привязывает обработчик только к одному состоянию. И данный с использованием этого метода будет выглядеть так:
st_waiting_connection_result.handle< msg_shutdown >( mbox,
&connection_handler::evt_shutdown ); st_waiting_auth_result.handle< msg_shutdown >( mbox, &connection_handler::evt_shutdown ); st_waiting_reconnection.handle< msg_shutdown >( mbox, &connection_handler::evt_shutdown ); st_closing_session.handle< msg_shutdown >( mbox, &connection_handler::evt_shutdown ); |
Что, на мой взгляд, гораздо хуже. Посему напрашивается вариант с переопределением operator+()
(st_waiting_connection_result +
st_waiting_auth_result +
st_waiting_reconnection +
st_closing_session) .handle< msg_shutdown >( mbox, &connection_handler::evt_shutdown ); |
Имена состояний не зря взяты такими длинными, это очень похоже на то, что используется в "боевых" приложениях.
Тут мне нужен второй совет: есть ли смысл определять подобным образом operator+() для привязывания обработчика сразу к нескольким состояниям? Или это еще один способ обсфукации кода?
Важное дополнение: старые методы и приемы никуда не уходят, они остаются. Причем не только для сохранения совместимости (ради этого они бы остались в любом случае), но и потому, что именно они сидят под капотом в новых, более компактных вариантах подписки. Поэтому пользователь сможет использовать любой удобный ему подход.
PS. Совсем уже "оторванный" вариант фантазия подсказала:
virtual void so_define_agent() override { st_normal.handle( m_notification_mbox, [this]( const msg_config_changed & evt ) { accept_new_config( evt ); } ); st_normal.handle< msg_shutdown >( m_notification_mbox, [this]() { initiate_shutdown(); } ); } |
virtual void so_define_agent() override { st_normal & m_notification_mbox += [this]( const msg_config_changed & evt ) { accept_new_config( evt ); }; st_normal & m_notification_mbox & signal< msg_shutdown > += [this]() { initiate_shutdown(); }; } |
Комментариев нет:
Отправить комментарий