我正在使用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
可以命名为bar
而method_2
可以命名为foo
),所有方法都返回true
或{{1}在每个类中,它们总是相同的,它们之间没有关系。
重构这些类的正确方法是什么?
注意:目前我正在考虑通过在每个模块中包含以下模块来重构类:
false
但我不知道这是否是实现我所期待的正确方法。此外,我不确定相关的优点和缺点......
答案 0 :(得分: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 :(得分: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
,表示foo
,bar
,baz
和quux
都是真的。
答案 2 :(得分: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