我有Number
模型的以下两种方法。
def track
number = sanitize(tracking)
case determine_type(number)
when 'UPS'
tracker = ups.track(:tracking_number => number)
self.carrier = Carrier.where(:name => 'UPS').first
self.service = tracker.service_type
self.destination_country = tracker.destination_country
self.destination_state = tracker.destination_state
self.destination_city = tracker.destination_city
self.origin_country = tracker.origin_country
self.origin_state = tracker.origin_state
self.origin_city = tracker.origin_city
self.signature = tracker.signature_name
self.scheduled_delivery = tracker.scheduled_delivery_date
self.weight = tracker.weight
tracker.events.each do |event|
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end
end
save
end
def update_number
case determine_type(number)
when 'UPS'
tracker = ups.track(:tracking_number => tracking)
self.carrier = Carrier.where(:name => 'UPS').first
self.service = tracker.service_type
self.destination_country = tracker.destination_country
self.destination_state = tracker.destination_state
self.destination_city = tracker.destination_city
self.origin_country = tracker.origin_country
self.origin_state = tracker.origin_state
self.origin_city = tracker.origin_city
self.signature = tracker.signature_name
self.scheduled_delivery = tracker.scheduled_delivery_date
self.weight = tracker.weight
last_event = self.events.ordered.first.occured_at
tracker.events.each do |event|
if last_event and (event.occurred_at > last_event)
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end
end
end
save
end
如您所见,许多代码都是重复的。当我开始添加十几个其他运营商(联邦快递,USPS,DHL等)时,问题就出现了......我的Number
模型变得庞大而且毛茸茸。
track
和update_number
之间唯一真正的区别在于update_number
作为if事件的比较,以检查来自运营商的事件是否比我最近发生的事件更新存储在数据库中,使用if last_event and (event.occurred_at > last_event)
行。
那么我该如何清理这些代码,以便我的模型不会那么胖呢?
答案 0 :(得分:5)
我建议的几件事:
希望这会有所帮助。
答案 1 :(得分:1)
这应该使用策略模式来解决。对于每个可能的跟踪器(DHL,UPS,......),它们将适当地处理创建和更新。
这样就会成为:
class Number
def track
tracker = get_tracker(tracking)
tracker.create_tracking(self)
save
end
def update_number
tracker = get_tracker(tracking)
tracker.update_tracking(self)
save
end
def get_tracker(tracking)
tracking_number = sanitize(tracking)
case determine_type(tracking_number)
when 'UPS'
UPSTracker.new(tracking_number)
when 'DHL'
DHLTracker.new(tracking_number)
end
end
end
class UPSTracker
def initialize(tracking_number)
@tracking_number = tracking_number
end
def create_tracking(number)
tracker = ups.track(:tracking_number => number)
update_number_properties(number, tracking)
# store events
tracker.events.each do |event|
create_new_event(event)
end
end
def update_tracking(number)
tracker = ups.track(:tracking_number => number)
update_number_properties(number, tracking)
last_event = self.events.ordered.first.occured_at
tracker.events.each do |event|
if last_event and (event.occurred_at > last_event)
create_new_event(event)
end
end
end
protected
def update_number_properties
number.carrier = Carrier.where(:name => 'UPS').first
number.service = tracker.service_type
number.destination_country = tracker.destination_country
number.destination_state = tracker.destination_state
number.destination_city = tracker.destination_city
number.origin_country = tracker.origin_country
number.origin_state = tracker.origin_state
number.origin_city = tracker.origin_city
number.signature = tracker.signature_name
number.scheduled_delivery = tracker.scheduled_delivery_date
number.weight = tracker.weight
end
def create_new_event
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end
end
此代码可以进一步改进,我想事件和跟踪的创建将在不同的运营商之间共享。所以共享基类也许。其次,在Number
内的两个方法中,我们调用get_tracker
:可能这个跟踪器可以在创建时(Number
- 实例)决定,并且应该被提取一次并存储在实例中变量
此外,我想补充一点,名称应该是有意义的,因此类Number
对我来说听起来不够有意义。名称应表达意图,并且最好与您的问题域中的名称和概念相匹配。
答案 2 :(得分:0)
关于你的代码的某些内容对我来说没有意义,组织有点奇怪,而且我没有足够的关于你的应用程序外观的上下文。在轨道中完成这样的事情的OOP方法非常简单;您也可以使用自己的策略,适配器甚至是Builder模式来执行此操作。
但是,有一些悬而未决的成果,你可以重构你的代码,所以常见的部分不那么突兀 - 这有点好,但create_events
仍然非常case
'y:< / p>
def track
create_events
end
def update_number
create_events {|e| last_event and (event.occurred_at > last_event) }
end
def create_events(&block)
case determine_type(number)
when 'UPS'
tracker = ups.track(:tracking_number => tracking)
self.carrier = Carrier.where(:name => 'UPS').first
self.assign_tracker(tracker)
end
tracker.events.each do |e|
self.create_event(e) unless (block_given? && !block.call(e))
end
save
end
def assign_tracker(tracker)
self.service = tracker.service_type
self.destination_country = tracker.destination_country
self.destination_state = tracker.destination_state
self.destination_city = tracker.destination_city
self.origin_country = tracker.origin_country
self.origin_state = tracker.origin_state
self.origin_city = tracker.origin_city
self.signature = tracker.signature_name
self.scheduled_delivery = tracker.scheduled_delivery_date
self.weight = tracker.weight
end
def create_event(event)
new_event = Event.new
new_event.number = self
new_event.city = event.city
new_event.state = event.state
new_event.postalcode = event.postal_code if event.postal_code
new_event.country = event.country
new_event.status = event.name
new_event.status_code = event.type
new_event.occured_at = event.occurred_at
new_event.save
end