Наблюдатели против обратных вызовов
Я думал об использовании наблюдателей или обратных вызовов.
Что и когда вы должны использовать наблюдателя?
F.e. вы можете сделать следующее:
# User-model
class User << AR
after_create :send_greeting!
def send_greeting!
UserNotifier.deliver_greeting_message(self)
end
end
#observer
class UserNotifier << AR
def greeting_message(user)
...
end
end
или вы можете создать наблюдателя и позволить ему смотреть, когда пользователи будут созданы...
Что вы рекомендовали?
Ответы
Ответ 1
Обратный вызов более короткий: вы передаете его функции, которая будет вызываться один раз. Это часть API, в которой вы обычно не можете вызывать функцию, не передавая также обратный вызов. Эта концепция тесно связана с тем, что делает функция. Обычно вы можете передавать только один обратный вызов.
Пример: Запуск потока и предоставление обратного вызова, который вызывается, когда поток завершается.
Наблюдатель живет дольше и может быть прикреплен/отсоединен в любое время. Для одного и того же объекта может быть много наблюдателей, и они могут иметь разные сроки жизни.
Пример: отображение значений из модели в пользовательском интерфейсе и обновление модели с пользовательского ввода.
Ответ 2
Одно действительно важное различие, о котором следует помнить, связанное с ответом Милана Новота, заключается в том, что обратные вызовы в ActiveRecord имеют возможность отменить вызываемое действие и все последующие обратные вызовы, где в качестве наблюдателей этого нет.
class Model < ActiveRecord::Base
before_update :disallow_bob
def disallow_bob
return false if model.name == "bob"
end
end
class ModelObserver < ActiveRecord::Observer
def before_update(model)
return false if model.name == "mary"
end
end
m = Model.create(:name => "whatever")
m.update_attributes(:name => "bob")
=> false -- name will still be "whatever" in database
m.update_attributes(:name => "mary")
=> true -- name will be "mary" in database
Наблюдатели могут наблюдать только, они не могут вмешиваться.
Ответ 3
Вы можете использовать наблюдателей как средство развязки или распределения ответственности. В базовом смысле - если ваш код модели становится слишком запутанным, начните думать об использовании наблюдателей для некоторого несущественного поведения. Реальная сила (по крайней мере, как мне кажется) наблюдателей заключается в их способности служить точкой соединения между вашими моделями и некоторой другой подсистемой, функциональность которой используется всеми (или некоторыми) из других классов. Предположим, вы решили добавить к своему уведомлению IM-уведомление - скажите, что вы хотите получать уведомления о некоторых (или всех) действиях CRUD некоторых (или всех) моделей в вашей системе. В этом случае использование наблюдателей было бы идеальным - ваша подсистема уведомлений будет полностью отделена от вашей бизнес-логики, и ваши модели не будут загромождать поведение, которое не относится к их бизнесу. Другим хорошим примером для наблюдателей будет подсистема аудита.