分享 <Ruby 元编程>思维导图 3 (方法)

flingjie · 2014年05月04日 · 最后由 flingjie 回复于 2014年05月05日 · 2644 次阅读

Ruby 是动态语言,没有静态类型检查,同时也提供了很多 java 等静态语言无法提供的编程技巧。 本章主要专注于消除重复代码的技巧,通过用两种不同的方式对一段代码的重构来展示 Ruby 的强大功能,涉及的知识点比较少。

  • 注 1: method_missing() 是 Kernel 中的一个实例方法,当 Ruby 找不到调用的方法时,它最后就会调用这个名为 method_missing() 的方法。

  • 注 2: 移除一个对象中的所有方法,以便把它们转换成幽灵方法。

重构例子

# 原始代码
class Computer
  def initialize(computer_id, data_source)
    @id = computer_id
    @data_source = data_source
  end
  def mouse
    info = @data_source.get_mouse_info(@id)
    price = @data_source.get_mouse_price(@id)
    result = "Mouse: #{info} ($#{price})"
    return "* #{result}" if price >= 100
    result
  end
  def cpu
    info = @data_source.get_cpu_info(@id)
    price = @data_source.get_cpu_price(@id)
    result = "Cpu: #{info} ($#{price})"
    return "* #{result}" if price >= 100
    result
  end
  def keyboard
    info = @data_source.get_keyboard_info(@id)
    price = @data_source.get_keyboard_price(@id)
    result = "Keyboard: #{info} ($#{price})"
    return "* #{result}" if price >= 100
    result
  end
  # ...
end
# 使用动态方法重构
class Computer
  def initialize(computer_id, data_source)
    @id = computer_id
    @data_source = data_source
    # 使用内省方式提取所有组件的名字
    data_source.methods.grep(/^get_(.*)_info$/) { Computer.define_component $1 }
  end

  def self.define_component(name)
    # 使用define_method()动态定义方法
    define_method(name) do
      # 使用send()方法集中处理
      info = @data_source.send "get_#{name}_info", @id
      price = @data_source.send "get_#{name}_price", @id
      result = "#{name.capitalize}: #{info} ($#{price})"
      return "* #{result}" if price >= 100
      result
    end
  end

  define_component :mouse
  define_component :cpu
  define_component :keyboard
end
#  使用幽灵方法重构
class Computer
  # 创建白板, 以免方法命名冲突
  instance_methods.each do |m|
    undef_method m unless m.to_s =~ /^__|method_missing|respond_to?/
  end

  def initialize(computer_id, data_source)
    @id = computer_id
    @data_source = data_source
  end

  # 在method_missing()中创建方法
  def method_missing(name, *args)
    super if !respond_to?(name)
    info = @data_source.send("get_#{name}_info", @id)
    price = @data_source.send("get_#{name}_price", @id)
    result = "#{name.to_s.capitalize}: #{info} ($#{price})"
    return "* #{result}" if price >= 100
    result
  end

  # 覆写respond_to?(),保证查询方法时返回正确结果
  def respond_to?(method)
    @data_source.respond_to?("get_#{method}_info") || super
  end
end
  • method_missing 而非 method_mission
  • Kernel 是个模块,不存在实例

@alixiaomiao 多谢指正,笔误 method_mission 已修改,模块不存在实例,但其中定义的方法也叫实例方法吧

不懂,完全晕、、、、

@sjzg001 自觉对本章内容理解把握的不够透彻,自身复制粘贴了部分内容,可能没把重点和思路表达清楚。不知哪里困扰在何处,哪里不懂?请反馈以求共同进步

#4 楼 @flingjie 呃是新手 不懂基础概念,和代码能够达到什么作用,解决什么问题。

@sjzg001 本章重点不是 ruby 中方法的一般特性和使用,主要讲有关代码重构的技术。通过 ruby 的特性消除重复代码,使代码简洁,遵循 DRY(Don‘t repeat yourself) 原则,提高可维护性。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号