...

пятница, 7 марта 2014 г.

Method chaining

В этом посте я поговорю о простом, но иногда полезном приеме программирования — method chaining. Также расскажу про потенциальный подводный камень, связанный с его использованием

Тест




Чтобы было интереснее, сначала небольшой тест.

1. Что такое method chaining? В суть этого приема?


2. Как он реализуется в С++?


3. Сможете ли вы придумать потенциально опасную ситуацию, связанную с импользованием этого приема?


Теория




Иногда, при использовании или написании больших классов возникает необходимость вызвать подряд несколько методов объекта этого класса. Обычно это выглядит так:

class worker
{
public:
void set_data(const data_t& d);
void process();
void send_result();
void print_log();
...
};

void foo()
{
worker w;
w.set_data(data_t{});
w.process();
w.send_result();
w.print_log();
...
}


Прием method chaining позволяет сократить этот код. Для этого мы в каждом нашем методе возвратим ссылку на наш объект и выстроим вызовы в цепочку.



class worker
{
public:
worker& set_data(const data_t& d){...; return *this;}
worker& process(){...; return *this;}
worker& send_result(){...; return *this;}
worker& print_log(){...; return *this;}
...
};

void foo()
{
worker w;
w.set_data(data_t{}).process().send_result().print_log();
...
}




Насколько я знаю, такой прием любят в Java. В С++ он не пользуется особой популярностью и я ни в коем случае не призываю его использовать, но знать о нем, думаю, не помешает.

Подводный камень




Строго говоря, то что я опишу ниже относится не столько к method chaining, сколько к порядку вычисления аргументов и вызовов функций, но тем не менее при использовании “цепочки вызовов” эти правила на первый взгляд могут работать неожиданно. Итак.

struct worker
{
worker& process(int& i)
{
i = 185;
return *this;
}
worker& print_result(const int& i)
{
std::cout <<"result: "<< i << std::endl;
return *this;
}
};

int main()
{
int data = 0;
worker w;
w.process(data).print_result(data+2);
}




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

Дело в том, что хотя стандарт и гарантирует, что process() будет вызвана перед print_result(), но не гарантируется, что перед аргумент функции print_result будет вычислен после выполнения process(). Соответственно, иногда в результате выполнения этого кода может быть выведено “2”.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий