假设我出于某种原因包装了ActiveRecord类,并且我已经定义了create
类方法。
class BusCreator
def self.create(attr)
bus = Bus.new(attr)
bus.departure_time = bus.arrival_time - bus.trip_duration
bus.save
bus
end
end
在create!
上定义BusCreator
方法的最佳方法是什么?显然,它应该执行与BusCreator.create
相同的逻辑,但应该调用save!
而不是save
。
答案 0 :(得分:1)
假设你有比上面一行更多的初始化逻辑,并且由于某种原因你不能把它放在AR模型本身,你可能会考虑以下几点:
class BusCreator
def self.create(attr)
bus = initialize(attr)
bus.save
bus
end
def self.create!(attr)
bus = initialize(attr)
bus.save!
bus
end
private
def self.initialize(attr)
bus = Bus.new(attr)
bus.departure_time = bus.arrival_time - bus.trip_duration
# ...more logic here
bus
end
end
答案 1 :(得分:0)
你可以这样做:
class BusCreator
def self.create(attr)
real_create(attr, :save)
end
def self.create!(attr)
real_create(attr, :save!)
end
#...
private
def self.real_create(attr, save_using)
bus = Bus.new(attr)
bus.departure_time = bus.arrival_time - bus.trip_duration
bus.send(save_using)
bus
end
end
答案 2 :(得分:0)
最佳答案在某种程度上取决于您希望create!
做什么。如果您希望它与create
执行相同的操作,但在失败时引发异常,则可以执行以下操作:
class BusCreator
def self.create(attr)
bus = build_bus(attr)
bus.save
bus
end
def self.create!(attr)
bus = create(attr)
if bus.new_record? # check if save succeeded
raise MyException, 'creation failed!'
end
bus
end
end
class MyException < StandardError; end
否则,这只是将方法的常用元素提取到另一个充当帮助者的方法中的问题:
class BusCreator
def self.create(attr)
bus = build_bus(attr)
bus.save
bus
end
def self.create!(attr)
bus = build_bus(attr)
bus.save!
bus
end
private
def self.build_bus(attr)
bus = Bus.new(attr)
bus.departure_time = bus.arrival_time - bus.trip_duration
end
end
这里有很多样式选项,如果你真的想减少重复,你可以做这样的事情:
class BusCreator
def self.create(attr)
bus = build_bus(attr)
end
def self.create!(attr)
bus = build_bus(attr, true)
end
private
def self.build_bus(attr, big_save=false)
bus = Bus.new(attr)
bus.departure_time = bus.arrival_time - bus.trip_duration
big_save ? bus.save! : bus.save
bus
end
end
答案 3 :(得分:0)
让我们看看你给出的例子。特别是这一行:
bus.departure_time = bus.arrival_time - bus.trip_duration
由于departure_time
取决于arrival_time
和trip_duration
,而Bus
又是同一对象的属性,因此没有理由将此代码放在Bus
之外。这意味着,您只需将其包装在方法中,然后调用该方法。
如果我们认为这是一个人为的例子,并且实际上你想做的事情比这更复杂,那么你真正需要的是new
类除了class Bus
# ...
def my_complex_method
self.departure_time = arrival_time - trip_duration
# some other complex stuff
# ...
end
# ...
# We are doing it here because BusCreator does not and should not
# know stuff internal to Bus
def self.new_with_departure_time(attr, other_optional_stuff)
bus = new(attr)
bus.my_complex_method
bus.process(other_optional_stuff)
bus
end
end
以外的新工厂。所以你用这样的工厂方法包装它:
save
请务必注意,此处的抽象与save!
和Bus#new
无关,但Bus#new
和my_complex_method
后跟save
。这是因为save!
和class BusCreator
def self.create(attr)
bus = Bus.new_with_departure_time(attr, other_stuff)
bus.save
bus
end
def self.create!(attr)
bus = Bus.new_with_departure_time(attr, other_stuff)
bus.save!
bus
end
end
表示不同的行为,因此具有与之关联的不同规格。所以使用这些2的代码实际上不应该是抽象的。
现在,回到我们之前定义的工厂,你会像这样使用它:
{{1}}