2009-07-25 58 views
4
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中使用元编程来减少某些重复性,如果有人可以提供一些建议。如何使用元编程来减少此Ruby代码中的冗余?

回答

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方法调用。

0

你确定你需要在这里减少冗余吗?这当然是可能的,但是你做的任何事情只会使代码更难理解,并不一定是净胜。

-1

你能想出一个更好的例子吗?

正如我之前说过的那样,在这里几乎不需要元编程。方法中功能的基本封装是可行的。

人们给出的任何示例都会被设计出来,而不是真正代表元编程的实际使用。

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

像这样的东西可以工作,所以你可以声明地定义“组件”(或其他任何东西)。这对于这种例子来说过于夸张,但是当你需要定义数十个/数百个这样的东西时,或者你把它作为某个框架的一部分(比如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 
0

我猜ü可能解决这个alreaday,反正这是我的选择:

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