我有大约11个看起来像这样的函数:
def pending_acceptance(order_fulfillments)
order_fulfillments.each do |order_fulfillment|
next unless order_fulfillment.fulfillment_time_calculator.
pending_acceptance?; collect_fulfillments(
order_fulfillment.status,
order_fulfillment
)
end
end
def pending_start(order_fulfillments)
order_fulfillments.each do |order_fulfillment|
next unless order_fulfillment.fulfillment_time_calculator.
pending_start?; collect_fulfillments(
order_fulfillment.status,
order_fulfillment
)
end
end
迭代始终相同,但next unless
条件不同。如果你想知道:它是next unless
和;
,因为RuboCop正在抱怨它。有没有更好的实施方案?我讨厌这个意大利面条代码。将条件传递给“iterate_it”函数等等......
编辑:不能只传递另一个参数,因为条件有时会加倍:
def picked_up(order_fulfillments)
order_fulfillments.each do |order_fulfillment|
next unless
order_fulfillment.handed_over_late? && order_fulfillment.
fulfillment_time_calculator.pending_handover?
collect_fulfillments(
order_fulfillment.status,
order_fulfillment
)
end
end
edit2:还有一个问题:如何切片符号,从状态获取用户角色?就像是:
:deliverer_started => :deliverer or 'deliverer'
?
答案 0 :(得分:4)
使用该参数决定要检查的条件时,可以传递另一个参数。只需将所有可能的条件作为lambda存储在哈希中:
FULFILLMENT_ACTIONS = {
pending_acceptance: lambda { |fulfillment| fulfillment.fulfillment_time_calculator.pending_acceptance? },
pending_start: lambda { |fulfillment| fulfillment.fulfillment_time_calculator.pending_acceptance? },
picked_up: lambda { |fulfillment| fulfillment.handed_over_late? && fulfillment.fulfillment_time_calculator.pending_handover? }
}
def process_fulfillments(type, order_fulfillments)
condition = FULFILLMENT_ACTIONS.fetch(type)
order_fulfillments.each do |order_fulfillment|
next unless condition.call(order_fulfillment)
collect_fulfillments(order_fulfillment.status, order_fulfillment)
end
end
被称为:
process_fulfillments(:pending_acceptance, order_fulfillments)
process_fulfillments(:pending_start, order_fulfillments)
process_fulfillments(:picked_up, order_fulfillments)
答案 1 :(得分:1)
你可以制作字符串数组
arr = ['acceptance','start', ...]
下一步:
arr.each do |method|
define_method ( 'pending_#{method}'.to_sym ) do |order_fulfillments|
order_fulfillments.each do |order_fulfillment|
next unless order_fulfillment.fulfillment_time_calculator.
send('pending_#{method}?'); collect_fulfillments(
order_fulfillment.status,
order_fulfillment
)
end
end
end
了解有关define_method
的更多信息答案 2 :(得分:1)
尽管next
很方便,但它在代码中迟到(r),因此更难以掌握。我首先会在列表中选择,然后执行操作。 (请注意,只有在您的“检查”没有order_fullfillment.send_email_and_return_false_if_fails
中的副作用时才可以这样做。
因此,如果测试可能很复杂,我会通过表达选择标准开始重构,然后撤出这些项目的处理(这些项目也与您给出的方法名称相匹配),在中间它可能看起来像这样:
def pending_acceptance(order_fulfillments)
order_fulfillments.select do |o|
o.fulfillment_time_calculator.pending_acceptance?
end
end
def picked_up(order_fulfillments)
order_fulfillments.select do |order_fulfillment|
order_fulfillment.handed_over_late? && order_fulfillment.
fulfillment_time_calculator.pending_handover?
end
end
def calling_code
# order_fulfillments = OrderFulFillments.get_from_somewhere
# Now, filter
collect_fulfillments(pending_start order_fulfillments)
collect_fulfillments(picked_up order_fulfillments)
end
def collect_fullfillments order_fulfillments
order_fulfillments.each {|of| collect_fullfillment(of) }
end
你仍然有11(+ 1)种方法,但你可以表达更多你正在做的事情 - 你的同事也会快速地了解发生的事情。鉴于你的例子和问题,我认为你应该寻求一个简单,富有表现力的解决方案。如果您更多"硬核",请使用其他解决方案中给出的功能更强大的lambda方法。另请注意,可以组合这些方法(通过传递迭代器)。
答案 3 :(得分:0)
您可以使用类似method_missing
的内容。
在课程的最底层,输入以下内容:
def order_fulfillment_check(method, order_fulfillment)
case method
when "picked_up" then return order_fulfillment.handed_over_late? && order_fulfillment.fulfillment_time_calculator.pending_handover?
...
... [more case statements] ...
...
else return order_fulfillment.fulfillment_time_calculator.send(method + "?")
end
end
def method_missing(method_name, args*, &block)
args[0].each do |order_fulfillment|
next unless order_fulfillment_check(method_name, order_fulfillment);
collect_fulfillments(
order_fulfillment.status,
order_fulfillment
)
end
end
根据您的要求,您可以检查method_name是否以“pending _”开头。
请注意,此代码未经测试,但应该位于该行的某个位置。
另外,作为旁注,order_fulfillment.fulfillment_time_calculator.some_random_method
实际上违反了law of demeter。你可能想要解决这个问题。