2012-12-18 104 views
0

我正在使用Ruby on Rails 3.2.9和Ruby 1.9.3。我有實施類似的方法爲,像下面的很多模型類:如何重構實現類似方法的模型類?

class ClassName_1 < ActiveRecord::Base 
    def great_method 
    self.method_1 
    end 

    def method_1 ... end 
end 

class ClassName_2 < ActiveRecord::Base 
    def great_method 
    result_1 = self.method_1 
    result_2 = self.method_2 

    result_1 && result_2 
    end 

    def method_1 ... end 
    def method_2 ... end 
end 

... 

class ClassName_N < ActiveRecord::Base 
    def great_method 
    result_1 = self.method_1 
    result_2 = self.method_2 
    ... 
    result_N = self.method_N 

    result_1 && result_2 && ... && result_N 
    end 

    def method_1 ... end 
    def method_2 ... end 
    ... 
    def method_N ... end  
end 

這些模型類的行爲幾乎是相同的(相同),因爲一些人的有一些不太以上方法的接口。所有方法都有不同的名稱(例如,method_1可能被命名爲barmethod_2可能被命名爲foo),所有返回truefalse,在每個類中總是相同,並且它們之間沒有關係。

什麼是重構這些類的正確方法?


:在這個時候,我想通過在每一個下面的模塊重構類:

module MyModule 
    def great_method 
    result_1 = self.respond_to?(:method_1) ? self.method_1 : true 
    result_2 = self.respond_to?(:method_2) ? self.method_2 : true 
    ... 
    result_N = self.respond_to?(:method_N) ? self.method_N : true 

    result_1 && result_2 && ... && result_N 
    end 
end 

但我不知道這是否是完成的正確方法我在找什麼。此外,我不確定相關的優點和缺點...

+0

您是否想過使用繼承?有一個主模型說'MainModel

+1

不幸的是,最好的抽象可能取決於具體的領域模型,所以它將有助於獲得關於領域模型的更多細節。例如,每個課程中的「method_1」總是相同的? 'method_1'和'method_2'之間有什麼關係? –

+0

@Vincent Paca - 我認爲繼承不是一件好事... – user12882

回答

1

看起來像你在正確的軌道上。如果method_n方法中是唯一的類,然後只是建立你已經有到每個ClassNameN繼承父類的模塊:

class SuperClassName < ActiveRecord::Base 
    def great_method 
    #... what you have in your module 
    end 
end 

class ClassNameN < SuperClassName 
    def method_1 ... end 
    def method_2 ... end 
end 

可能會有另外的方法,供您根據分解出的代碼發生的事情在你的method_n方法中,但不可能沒有更多細節。

+1

我認爲(不僅僅是我......)繼承與「包含MyModule」方法相比有許多缺點。這是爲了我試圖通過使用後一種方法來重構代碼。 – user12882

0

你可以抽象出great_method像這樣的東西:

require 'active_support/concern' 

module Greatest 
    extend ActiveSupport::Concern 

    module ClassMethods 
    attr_accessor :num_great_methods 

    def has_great_methods(n) 
     @num_great_methods = n 
    end 
    end 

    def great_method 
    (1..self.class.num_great_methods).each do |n| 
     return false unless self.__send__("method_#{n}") 
    end 
    true 
    end 
end 

class ClassName_3 
    include Greatest 

    has_great_method 3 

    # stub out the "method_*" methods 
    (1..3).each do |n| 
    define_method "method_#{n}" do 
     puts "method_#{n}" 
     true 
    end 
    end 
end 

puts ClassName_1.new.greatest 
+0

對不起,但方法* *有不同的名稱(例如,'method_1'可以命名爲'bar','method_2'可以命名爲'foo')。 – user12882

+0

只是更新'has_great_method'來取一個'* args'數組,所以你可以用'has_great_methods:foo,:bar'來調用它,儘管當抽象的東西看起來不像抽象的時候。 –

1

我會用元編程解決方案在一定程度上清理它。

module BetterCode 
    extend ActiveSupport::Concern 

    module ClassMethods 
    def boolean_method(name, *components) 
     define_method name do 
     components.all? { |c| send c } 
     end 
    end 
    end 
end 

而在你的機型:

class MyModel < ActiveRecord::Base 
    include BetterCode 

    boolean_method :great_method, :foo, :bar, :baz, :quux 
end 

MyModel實例會再到great_method迴應用布爾值,指示foobarbazquux是否是全真。

+0

或者使用'ActiveSupport :: Concern'來更加清晰。 –

+0

編輯我使用'ActiveSupport :: Concern'的答案。 – Finbarr

相關問題