【问题标题】:Chain of Responsibility and alias_method problems in RubyRuby 中的责任链和 alias_method 问题
【发布时间】:2010-06-30 04:58:30
【问题描述】:

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

  • 有时我在尝试使用 alias_method 时收到一个方法未定义的错误,我认为这是因为该类未加载或其他原因,因此我明确执行发送以获取该方法
  • 我得到一堆无限链,其中别名函数 (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

然后,我有一个设置对象:

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

【问题讨论】:

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


    【解决方案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,它将被退回。否则,它将从 next_link 获取 usable_setting。如果那个有 api_key/active_days,它将被返回,否则它将从 next_link 获取 usable_setting。等等。

    【讨论】:

    • 嘿,这个答案很好,但我认为我遇到的主要问题是用超魔方式定义方法。我想这样做的原因是我有很多链式函数,作为一个程序员,我宁愿花 10 个小时来弄清楚如何避免打字,而不是花 2 个小时把它全部输入。我最终做到了创建一个代表链接的单独类,我认为在 activerecord 中很难做到这一点,因为它创建了自己的别名函数。
    • 如果你想神奇地做到这一点,你所要做的就是:[:api_key, :active_days].each{|meth| define_method(meth){super || next_usable_setting.send(meth)}}。但坦率地说,我宁愿单独定义它们,因为它读起来更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多