eao197 on the Web
Сайт Евгения Охотникова
[ Главная | Проекты | Описания | Об авторе | Лицензия ]

C++ tricks: partial_copy_ctor

В одном из проектов столкнулся недавно с задачей перемаршрутизации сообщений. Eсть два компонента, каждый из которых отсылает другому какие-то сообщения. А между ними оказывается третий компонент маршрутизатор, который перехватывает сообщения первого компонента, чуть-чуть модифицирует их и передает второму компоненту. Аналогичные действия маршрутизатор предпринимает и с сообщениями второго компонента.

Изначально я поступал с перемаршрутизируемыми сообщениями очень просто: создавал новый объект сообщение при помощи конструктора копирования, а затем с помощью методов setter-ов изменял значения необходимых атрибутов. Т.е. делал что-то вроде:

some_message_t outgoing( original );
outgoing.set_originator_trx( modify_trx( original.query_originator_trx(), some_params ) );
outgoing.set_recipient_trx( modify_trx( original.query_recipient_trx(), another_params ) );
...

Очень простое и надежное решение. Особенно хорошо было то, что сами объекты сообщения со временем могли расширяться дополнительными атрибутами, про которые маршрутизатор мог совсем не знать. Но которые бы при таком подходе все равно копировались в исходящее сообщение.

Но мне не нравилось то, что для переопределяемых атрибутов инициализация осуществлялась дважды: сначала в конструкторе копирования, затем в setter-е. Проблему я видел в том, что в моем случае переопределялись как раз атрибуты, чья инициализация была весьма дорогостоящей. Поэтому от лишнего присваивания хотелось избавиться. Но при этом не хотелось использовать конструкторы, в которые нужно было бы передавать значения атрибутов -- это бы повысило стоимость сопровождения при добавлении в сообщения новых атрибутов, про которые маршрутизатору знать не обязательно.

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

class some_message_t
  {
  public :
	 ...
    some_message_t(
      const trx_id_t & originator_trx,
      const trx_id_t & recipient_trx,
      const some_message_t & original );
    ...
  };

После чего код в маршрутизаторе стал похож на:

some_message_t outgoing(
  modify_trx( original.query_originator_trx(), some_params ),
  modify_trx( original.query_recipient_trx(), another_params ),
  original );

В результате, с помощью такого частично копирующего конструктора удалось и снизить накладные расходы на копирование объекта сообщения, и сохранить возможность расширения сообщений новыми атрибутами, не требуя изменять код маршрутизатора.

© 2003-2005 Е.А. Охотников
$LastChangedDate: 2005-04-29 08:42:34 +0400 (Пт, 29 апр 2005) $
e-mail



Hosted by uCoz