2009-07-25 57 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