В этом посте я поговорю о простом, но иногда полезном приеме программирования — method chaining. Также расскажу про потенциальный подводный камень, связанный с его использованием
Чтобы было интереснее, сначала небольшой тест.
Иногда, при использовании или написании больших классов возникает необходимость вызвать подряд несколько методов объекта этого класса. Обычно это выглядит так:
Насколько я знаю, такой прием любят в Java. В С++ он не пользуется особой популярностью и я ни в коем случае не призываю его использовать, но знать о нем, думаю, не помешает.
Строго говоря, то что я опишу ниже относится не столько к method chaining, сколько к порядку вычисления аргументов и вызовов функций, но тем не менее при использовании “цепочки вызовов” эти правила на первый взгляд могут работать неожиданно. Итак.
Этот код скомпилируется без предупреждений и ошибок. Но результаты выполнения могут отличаться на разных компиляторах.
Дело в том, что хотя стандарт и гарантирует, что process() будет вызвана перед print_result(), но не гарантируется, что перед аргумент функции print_result будет вычислен после выполнения process(). Соответственно, иногда в результате выполнения этого кода может быть выведено “2”.
Тест
Чтобы было интереснее, сначала небольшой тест.
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.
Комментариев нет:
Отправить комментарий