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”.

ссылка на оригинал статьи http://habrahabr.ru/post/215059/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *