1.介绍使用动态调用和动态定义方法来消除重复代码
2.使用Ghost Method和动态代理技术消除重复代码
class DS def initialize(id, m_info, m_price, cpu_info, cpu_price) @id = id @m_info = m_info @m_price = m_price @cpu_info = cpu_info @cpu_price = cpu_price end def get_mouse_info(id) @m_info end def get_mouse_price(id) @m_price end def get_cpu_info(id) @cpu_info end def get_cpu_price(id) @cpu_price end end
修改了元编程书中的例子,原意是输出产品信息,价格大于100的部件,前面加上*号做标示,这些不是重点,重点是如何
通过元编程来减少代码中的重复
第一种方法:使用动态方法和动态派发
class Computer #使用白板技术(Blank State),即在代理类中删除继承来的方法 #Computer 继承了父类Object和Kernel的一些方法 #如果Computer调用了这些方法,是真实存在的方法,则不会进入到method_missing方法中 instance_methods.each do |m| undef_method m unless m.to_s =~ /^__|method_missing|respond_to?|object_id/ end def initialize(computer_id, ds) @id = computer_id @ds = ds end def method_missing(name, *args) super if !respond_to?(name) info = @ds.send "get_#{name}_info", args[0] price = @ds.send "get_#{name}_price", args[0] result = "#{name.capitalize} : #{info} ($#{price})" return "* #{result}" if price >100 result end #为什么要重写respond_to?方法 #动态生成的方法,不会出现在Object#methods中, #所以cmp.respond_to?(:mouse) 返回的是false,而实际上程序运行时确实是生成了mouse这个方法 #为了解决这个问题,需要覆写respond_to?方法 def respond_to?(method) @ds.respond_to?("get_#{method}_info") || super end end ds = DS.new(1, "mourse", 99, "cpu", 103) cmp = Computer.new(1, ds) puts cmp.cpu puts cmp.mouse puts cmp.respond_to?(:mouse)
第二种方法:使用动态代理和白板技术
class Computer def initialize(computer_id, ds) @id = computer_id @ds = ds #Pattern Dispatch模式派发,Computer初始化的时候,获取DS的方法,解析出 #cpu和mouse,然后通过define_componet来定义方法 cpu 和 mouse ds.methods.grep(/^get_(.*)_info$/){ Computer.define_component $1} end #使用define_method动态的定义方法 def self.define_component(name) define_method(name) { info = @ds.send "get_#{name}_info", @id price = @ds.send "get_#{name}_price", @id result = "#{name.capitalize} : #{info} ($#{price})" return "* #{result}" if price >100 result } end end #1 #puts Computer.instance_methods #Computer不进行初始化,则没有cpu和mouse方法 #2 #ds = DS.new(1, "mourse", 99, "cpu", 103) #cmp = Computer.new(1, ds) #puts Computer.instance_methods #初始化后,Computer就产生了cpu和mouse方法 ds = DS.new(1, "mourse", 99, "cpu", 103) cmp = Computer.new(1, ds) puts Computer.instance_methods puts cmp.cpu puts cmp.mouse puts cmp.respond_to?(:mouse)