Clojure: Наблюдатели
Помимо атомов и агентов, в Clojure существуют наблюдатели, их основное использование заключается в наблюдении за изменяемым ресурсом (издалека напоминает супервизоров из Elixir/Erlang, но более простых).
Рассмотрим несколько примеров:
(def my-atom (atom 0))
; добавим наблюдателя для нашего атома, у наблюдателя должно быть уникальное имя
(add-watch my-atom "my-watcher"
; обратите внимание на аргументы, которые передаются в функцию, вызываемую наблюдателем при изменении состояния
(fn [key variable old-state new-state]
(println key variable old-state new-state)))
#object[clojure.lang.Atom 0x673d073a {:status :ready, :val 0}]
(swap! my-atom inc)
my-watcher #object[clojure.lang.Atom 0x673d073a {:status :ready, :val 1}] 0 1
1
(swap! my-atom (fn [state] (* state 4)))
my-watcher #object[clojure.lang.Atom 0x673d073a {:status :ready, :val 4}] 1 4
4
(swap! my-atom (fn [state] (* state 4)))
my-watcher #object[clojure.lang.Atom 0x673d073a {:status :ready, :val 16}] 4 16
16
; теперь уберем наблюдателя
(remove-watch my-atom "my-watcher")
#object[clojure.lang.Atom 0x673d073a {:status :ready, :val 16}]
(swap! my-atom inc)
17Наблюдатели позволяют упростить процесс логирования и отладки и сделать жизнь разработчика чуть легче, однако, никто не мешает добавить в функцию наблюдателя какие-либо внешние мутации (например, мутация другого ресурса), но лучше так не делать :)
Задание
Создайте атом (начальное значение 0) и добавьте к нему наблюдателя, который при изменении атома выводит сообщение (с помощью print) в следующем виде Change state from x to y., где x — прошлое состояние атома, а y — новое состояние атома. Затем дважды увеличьте атом на 1, потом уменьшите его значение на 1.
Полезное
Ваше упражнение проверяется по этим тестам
(ns watchers-test
(:require [test-helper :refer [assert-output]]))
(assert-output "Change state from 0 to 1.Change state from 1 to 2.Change state from 2 to 1.")Решение учителя откроется через:
20:00
