class Device
def initialize(device_id, data_resource)
@id = device_id
@data_resource = data_resource
end
def display_device
mode = @data_resource.get_display_device_mode(@id)
presets = @data_resource.get_display_device_presets(@id)
summary = "display_device: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
def chip
mode = @data_resource.get_chip_mode(@id)
presets = @data_resource.get_chip_presets(@id)
summary = "chip: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
def input_device
mode = @data_resource.get_input_device_mode(@id)
presets = @data_resource.get_input_device_presets(@id)
summary = "input_device: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
end
从上面的代码中可以看出,这些方法中存在相当多的冗余。 无论元编程是否是减少此冗余的最佳方法,我希望学习如何在Ruby中使用元编程来减少某些重复性,如果有人可以提供一些建议的话。
答案 0 :(得分:6)
这是一个使用元编程的版本,虽然我也会通过将它放在它所属的方法中来删除重复。
class Device
def initialize(device_id, data_resource)
@id = device_id
@data_resource = data_resource
end
def resource_summary(resource_name)
mode = @data_resource.send("get_#{resource_name}_mode", @id)
presets = @data_resource.send("get_#{resource_name}_presets", @id)
summary = "#{resource_name}: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
def self.resource_accessor(*names)
names.each {|resource| define_method(resource) {resource_summary resource}}
end
resource_accessor :display_device, :chip, :input_device
end
如果您真的不想为该功能制作方法,则只需将resource_summary
方法调用替换为resource_summary
方法的正文。
答案 1 :(得分:3)
这样的东西可以工作,所以你可以声明性地定义'组件'(或者它们是什么)。对于这类示例来说这是过度的,但是当你需要定义几十个/几百个这样的东西时,你可以使用它,或者你把它作为某个框架的一部分(比如rails)。
component
类级别方法通常会存在于包含在类中的其他模块中,而不是像这样将其内联声明为内联语。
class Device
class << self
def component(component_name)
define_method(component_name) do
mode = @data_resource.send("get_#{component_name}_mode", @id)
presets = @data_resource.send("get_#{component_name}_presets", @id)
summary = "#{component_name} : #{mode} ($#{presets})"
presets == "XTC909" ? "* #{summary}" : summary
end
end
end
component :display_device
component :chip
component :input_device
def initialize(device_id, data_resource)
@id = device_id
@data_resource = data_resource
end
end
您可以使用以下内容驾驶它:
class DataResource
def method_missing(method, *args)
# puts "called #{method} with:#{args.inspect}"
"#{method}-#{args.join(':')}"
end
end
device = Device.new("ID123", DataResource.new)
puts device.display_device
puts device.chip
puts device.input_device
答案 2 :(得分:2)
显然,有些名字应该改变......
def display_device
i_heart_meta_programming("display_device")
end
def chip
i_heart_meta_programming("chip")
end
def input_device
i_heart_meta_programming("input_device")
end
def i_heart_meta_programming(what_to_get)
mode = @data_resource.send("get_#{what_to_get}_mode", @id)
mode = @data_resource.send("get_#{what_to_get}_presets", @id)
summary = "#{what_to_get}: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
答案 3 :(得分:0)
您确定需要在这里减少冗余吗?这当然是可能的,但是你做的任何事情都会让代码更难理解,也不一定是净胜利。
答案 4 :(得分:0)
我想你可能解决了这个问题,无论如何这是我的选择:
class Device
def initialize(device_id, data_resource)
@id,@data_resource = device_id, data_resource
end
%w{display_device chip input_device}.each do |met|
define_method met do
mode = @data_resource.send("get_#{met}_mode", @id)
presets = @data_resource.send("get_#{met}_presets",@id)
summary = "#{met}: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
end
end
答案 5 :(得分:-1)
你能想出一个更好的例子吗?
正如我之前所说的那样,这里几乎不需要元编程。方法中功能的基本封装可行。
人们给出的任何例子都是人为的,并不能真正代表元编程的现实用法。