观察者与回调函数

35

我想过使用观察者或回调函数。何时应该使用观察者?

例如,你可以这样做:

# 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

或者你可以创建一个观察者,并让它观察用户何时被创建...

你有什么建议?

3个回答

45

需要牢记的一个非常重要的区别与 Milan Novota 的答案有关,那就是 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

观察者只能观察,不能干预。


19
在Rails 3.1中,观察者可以通过在before_*回调中返回false来取消保存操作,并且还可以在after_*回调中抛出异常来异常取消操作。 - Joel Wickard
谢谢jrizza,我遇到了类似的情况,其中一个观察者的失败导致记录无法保存,我认为这是一个不良后果。 - Pratik Khadloya
2
是的,这很奇怪,它们不再是观察者了,观察者中的异常将导致提交失败并使用户获得异常屏幕。对我来说没有意义。 - Amala

30

您可以使用观察者作为解耦或责任分配的手段。基本上,如果您的模型代码变得太 messy,开始考虑为一些非必要行为使用观察者。观察者真正的强大之处(至少在我看来)在于它们作为连接点的能力,将您的模型与一些其他子系统连接起来,这些子系统的功能被所有(或部分)其他类使用。假设您决定向应用程序添加IM通知- 例如,您希望收到有关系统中某些(或所有)模型的一些(或所有)CRUD操作的通知。在这种情况下,使用观察者是理想的- 您的通知子系统将完全与您的业务逻辑分离,您的模型不会混杂着不属于它们业务范畴的行为。观察者的另一个很好的用例是审计子系统。


14

回调函数更短暂:您将其传递到要调用一次的函数中。它是 API 的一部分,通常情况下,您不能在没有传递回调函数的情况下调用该函数。这个概念与函数的操作紧密相连。通常,只能传递单个回调函数。

例如:运行线程并提供一个回调函数,当线程终止时调用该函数。

观察者生存期更长,可以随时附加/分离。对于同一件事情可能有许多观察者,它们的生命周期可能不同。

例如:在 UI 中显示模型的值,并从用户输入更新模型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接