Ruby中的责任链和alias_method问题

时间:2010-06-30 04:58:31

标签: ruby chain-of-responsibility alias-method

我正在尝试在Ruby和ActiveRecord中实现一个多态对象的责任链模式。我遇到了一些问题。

  • 有时候我得到一个错误,当我尝试alias_method时没有定义方法,我认为这是因为没有加载类或者其他东西所以我明确地做了一个send来获取方法
  • 我得到了一堆无限链,其中别名函数(original_method)调用调用original_method的方法。我想知道这是否是因为当你将一个已被覆盖的方法别名时,你实际上是在将“original_method”作为别名方法的副本。
  • 我目前正在解决这个问题,因为像“chained”这样的函数会返回一个带有所有已定义方法的Setting的子类,但很奇怪为什么alias_method在类中有这么多问题。

以下是一个例子:

class Hospital
  has_one :setting, :as => :settable
  belongs_to :administrative_area

  def next_link
    adminstrative_area
  end

  def usable_setting
    setting ? setting : next_link.usable_setting
  end
end

然后,我有一个Setting对象:

class Setting < ActiveRecord::Base

belongs_to :settable, :polymorphic => true

def chained
  %w(api_key active_days).each do |method|

    # this is here because otherwise the method isn't defined,
    # it's almost as while it's going up, the metaclass doesn't have the columns
    # until it loads, probably will be fixed if we cache classes
    self.send method.to_sym

    (class << self; self; end).class_eval do

      define_method method do |*args|
        alias_method "original_#{method}", method
        my_setting = send("original_#{method}")
        if my_setting.nil? or my_setting.empty?
          settable.next_link.usable_setting.chained.send(method)
        else
          return my_setting
        end
      end
    end
  end
  self
end
end

1 个答案:

答案 0 :(得分:1)

你似乎过于复杂。似乎您正在尝试查看api_key和active_days是否存在,如果不存在,则从其他地方获取它。

这是正确的方法,假设api_key和active_days是表中的列:

class Setting < ActiveRecord::Base

  belongs_to :settable, :polymorphic => true

  def api_key
    super || settable.next_link.usable_setting.api_key
  end

  def active_days
    super || settable.next_link.usable_setting.active_days
  end
end

您可以稍微重构一下以保持清晰并删除重复。

class Setting < ActiveRecord::Base

  belongs_to :settable, :polymorphic => true

  def api_key
    super || next_usable_setting.api_key
  end

  def active_days
    super || next_usable_setting.active_days
  end

  private
  def next_usable_setting
    settable.next_link.usable_setting
  end
end

所以在这种情况下通知 - 如果你有api_key / active_days可用,它将被返回。 Otehrwise,它将从next_link获取useful_setting。如果那个有api_key / active_days,它将被返回,否则它将从next_link获取useful_setting。等