Возможно, это не новые идеи, но я не видел их в письменном виде. Часто мы пишем такие функции, как «UpdateFoo» или «RefreshFoo». Их цель, как правило, состоит в том, чтобы обновить некоторое устаревшее состояние на основе текущего состояния их входных данных, возможно, кэшируя дорогостоящие вычисления, и они обычно вызываются обработчиками событий или периодическими таймерами. Достаточно просто, не так ли? В основном, но существует миллиард способов написания такого кода, поэтому наличие общих идиом и правил может сделать ваш код более понятным и, следовательно, менее глючным. Вот некоторые из них, которые я считаю полезными:
- Они не должны принимать никаких аргументов, за исключением указания на то, какое состояние нуждается в обновлении (что может быть неявным в 1) самой функции, например UpdateFoo, обновляет Foo, 2) конкретном экземпляре объекта, например bar.Update () обновляет панель или 3) некоторые явные аргументы, указывающие на это, например, Update(baz) обновляет baz). Сама функция обновления должна иметь возможность отрисовывать все необходимые ей состояния ввода без их передачи. Обычный шаблон для текстового поля заключается в отправке текущего текста своим обработчикам событий изменения, таким как функция обновления. Это нехорошо, потому что теперь функция обновления может использоваться только текстовым полем. Вместо этого функция обновления должна сохранять ссылку на поле и сама извлекать текущий текст. Затем его могут использовать другие обработчики событий, чтобы получать уведомления о других изменениях, о которых он заботится.
- Они должны быть квазиидемпотентными. Это означает, что звонить им всегда безопасно и правильно. Обычно несколько путей кода вызывают функции обновления независимо (и исправление ошибки аннулирования кеша должно быть таким же простым, как добавление отсутствующего вызова обновления!), и если обновление каким-то образом зависит от того, сколько раз оно вызывается, вы спрашиваете для ошибок. Если вычисление обновления требует больших затрат, вы можете отложить вычисление, чтобы вы выполняли его только один раз в какой-то более поздний момент — это в основном пакетная обработка (глобальная очередь сообщений JS — отличный шаблон для этого). ПРИМЕЧАНИЕ. Я говорю квази-идемпотентный, потому что по-настоящему идемпотентная функция никогда не изменит результаты после первого вызова. Но очевидно, что весь смысл функций обновления заключается в изменении результатов всякий раз, когда меняются входные данные, независимо от количества вызовов. Так что, точнее, они должны быть идемпотентными, если их входные данные не меняются.
- Функции Set должны быть умны при вызове функций обновления. Это довольно просто: если (текущий != новый) { текущий = новый; ОбновитьФоо(); Панель обновлений(); }. Здесь Foo и Bar зависят от «текущего». Но если SetCurrent на самом деле не дает нового значения, SetCurrent не вызывает обновления. Вы также можете сделать так, чтобы функции обновления делали это сами, например, запоминая предыдущие значения входных данных, но это становится громоздким. Очевидно, что если есть какая-то работа, которую нужно пропустить, но об этом будет знать только сама функция обновления, то вы должны сделать это там (например, может быть, ввод является числом с плавающей запятой, но обновление заботится только об округленном значении). Но в худшем случае, если вы забудете это сделать, ничего страшного, потому что они квазиидемпотентны!
- Если ваша функция обновления может вызывать другие функции обновления, сделайте это также эффективно: prevValue = value; значение = ВычислитьНовоеЗначение(); if (prevValue != значение) CallOtherUpdates();
Я надеюсь, что это полезно. Удачи!