Мы находимся в процессе изменения того, как наше приложение AS3 взаимодействует с нашим бэкэндом, и мы находимся в процессе внедрения системы REST для замены нашей старой.
К сожалению, разработчик, который начал работу, сейчас находится в длительном отпуске по болезни, и он был передан мне. Я работал с ним в течение прошлой недели или около того сейчас, и я понимаю систему, но есть одна вещь, которая беспокоит меня. Кажется, что функции часто передаются в функции. Например, наш класс, который делает вызов нашим серверам, принимает функцию, которую он затем вызывает и передает объект, когда процесс завершен, ошибки обработаны и т. Д.
Это вызывает у меня «плохое предчувствие», когда я чувствую, что это ужасная практика, и я могу подумать о некоторых причинах, почему, но мне нужно подтверждение, прежде чем я предложу переработать систему. Мне было интересно, есть ли у кого-нибудь опыт с этой возможной проблемой?
источник
Ответы:
Это не проблема.
Это известная техника. Это функции высшего порядка (функции, которые принимают функции в качестве параметров).
Этот тип функций также является основным строительным блоком в функциональном программировании и широко используется в функциональных языках, таких как Haskell .
Такие функции не являются плохими или хорошими - если вы никогда не сталкивались с понятием и техникой, их может быть сложно сначала понять, но они могут быть очень мощными и хорошим инструментом для использования в вашем инструментальном поясе.
источник
Они не просто используются для функционального программирования. Их также можно назвать обратными вызовами :
Подумайте об асинхронном коде на секунду. Вы передаете функцию, которая, например, отправляет данные пользователю. Только после завершения кода вы вызываете эту функцию с результатом ответа, который затем используется функцией для отправки данных обратно пользователю. Это изменение мышления.
Я написал библиотеку, которая получает данные Torrent из вашей семенной коробки. Вы используете неблокирующий цикл событий, чтобы выполнить эту библиотеку и получить данные, а затем вернуть их пользователю (скажем, в контексте веб-сокета). Представьте, что у вас есть 5 человек, связанных в этом цикле событий, и один из запросов на получение чьих-то торрент-данных. Это заблокирует весь цикл. Поэтому вам нужно думать асинхронно и использовать обратные вызовы - цикл продолжает работать, а «передача данных обратно пользователю» запускается только после того, как функция закончила выполнение, так что ждать его не приходится. Огонь и забудь.
источник
Это неплохая вещь. На самом деле это очень хорошая вещь.
Передача функций в функции настолько важна для программирования, что мы изобрели лямбда-функции как сокращение. Например, можно использовать лямбда-выражения с алгоритмами C ++ для написания очень компактного, но выразительного кода, который позволяет универсальному алгоритму использовать локальные переменные и другие состояния для таких вещей, как поиск и сортировка.
Объектно-ориентированные библиотеки также могут иметь обратные вызовы, которые по сути являются интерфейсами, задающими небольшое количество функций (в идеале одну, но не всегда). Затем можно создать простой класс, который реализует этот интерфейс, и передать объект этого класса в функцию. Это краеугольный камень в программировании , управляемом событиями , когда код уровня платформы (возможно, даже в другом потоке) должен вызывать объект для изменения состояния в ответ на действие пользователя. Java- интерфейс ActionListener является хорошим примером этого.
Технически, функтор C ++ также является типом объекта обратного вызова, который использует синтаксический сахар
operator()()
, чтобы сделать то же самое.Наконец, есть указатели на функции в стиле C, которые должны использоваться только в C. Я не буду вдаваться в подробности, я просто упомяну их для полноты. Другие абстракции, упомянутые выше, намного лучше и должны использоваться в языках, которые их имеют.
Другие упоминали о функциональном программировании и о том, что передача функций очень естественна в этих языках. Лямбды и обратные вызовы - это то, как процедурные языки и языки ООП имитируют это, и они очень мощные и полезные.
источник
Как уже было сказано, это неплохая практика. Это просто способ отделить и разделить ответственность. Например, в ООП вы должны сделать что-то вроде этого:
Универсальный метод делегирует определенную задачу - о которой он ничего не знает - другому объекту, который реализует интерфейс. Универсальный метод знает только этот интерфейс. В вашем случае этот интерфейс будет функцией для вызова.
источник
В общем, нет ничего плохого в передаче функций другим функциям. Если вы делаете асинхронные вызовы и хотите что-то сделать с результатом, вам понадобится какой-то механизм обратного вызова.
Есть несколько потенциальных недостатков простых обратных вызовов:
С простыми веб-сервисами способ, которым вы это делаете, работает нормально, но становится неловко, если вам нужна более сложная последовательность вызовов. Хотя есть несколько альтернатив. Например, в JavaScript произошел сдвиг в сторону использования обещаний ( что такого хорошего в обещаниях javascript ).
Они по-прежнему включают передачу функций в другие функции, но асинхронные вызовы возвращают значение, которое принимает обратный вызов, а не принимает обратный вызов непосредственно. Это дает больше гибкости для составления этих вызовов вместе. Нечто подобное можно реализовать довольно легко в ActionScript.
источник