Наблюдатели против обратных вызовов

Я думал об использовании наблюдателей или обратных вызовов. Что и когда вы должны использовать наблюдателя?

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 некоторых (или всех) моделей в вашей системе. В этом случае использование наблюдателей было бы идеальным - ваша подсистема уведомлений будет полностью отделена от вашей бизнес-логики, и ваши модели не будут загромождать поведение, которое не относится к их бизнесу. Другим хорошим примером для наблюдателей будет подсистема аудита.