我怎样才能干燥这段代码并清理我的模型?
对于 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
正如您所看到的,很多代码都是重复的。当我开始添加十几家其他承运商(FedEx、USPS、DHL 等)时,问题就出现了……我的 Number
模型变得又大又毛茸茸的。
track
和 update_number
之间的唯一真正区别在于,update_number
作为事件周围的 if 比较,以检查来自运营商的事件是否更新比我使用 if last_event and (event.occurred_at > last_event)
行存储在数据库中的最新事件。
那么我怎样才能清理这段代码,这样我的模型就不会变得那么胖呢?
I have the following two methods for a Number
model.
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
As you can see, a lot of code is duplicated. And the problem becomes when I start adding the dozen or so other carriers (FedEx, USPS, DHL, etc)...my Number
model gets big and hairy fast.
The only real difference between track
and update_number
is that update_number
as an if comparison around the events to check if the events from the carrier are more recent than the latest events I have stored in the database, using that if last_event and (event.occurred_at > last_event)
line.
So how can I clean up this code so my model doesn't get so fat?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我建议的几件事:
希望这有帮助。
A couple of things I would suggest:
Hope this helps.
这应该使用策略模式来解决。对于每个可能的跟踪器(DHL、UPS...),将适当地处理创建和更新。
所以这会变成这样:
这个代码可以进一步改进,我想事件和跟踪的创建将在不同的运营商之间共享。所以也许是一个共享基类。其次,在
Number
内部的两个方法中,我们调用get_tracker
:这个跟踪器可能可以根据(Number
实例的)创建时间来决定,并且应该获取一次并存储在实例变量中。此外,我想补充一点,名称应该有意义,因此类
Number
对我来说听起来不够有意义。名称应该表达意图,并且最好与问题域中的名称和概念相匹配。This should be solved using the Strategy pattern. For each possible tracker (DHL, UPS, ...) that will handle the creating and updating appropriately.
So that would become something like:
This code could be further improved, I imagine the creating of events and trackings will be shared over the different carriers. So a shared base-class maybe. Secondly, in two methods inside
Number
we call theget_tracker
: probably this tracker can be decided upon creation time (of theNumber
-instance) and should be fetched once and stored inside an instance variable.Furthermore I would like to add that names should be meaningful, so a class
Number
does not sound meaningful enough to me. A name should express intent, and preferably match the names and concepts from your problem domain.您的代码中的某些内容对我来说没有意义,组织有点奇怪,而且我对您的应用程序的外观没有足够的背景信息。在 Rails 中完成类似的 OOP 方式非常简单;您还可以推出自己的策略、适配器,甚至构建器模式来执行此操作。
但是,有一些容易实现的目标,您可以重构代码,使公共部分不那么引人注目——这更好一点,但是
create_events
仍然非常case
' y:Something about your code doesn't make sense to me, the organization is a little strange and I don't have enough context on what your app looks like. The OOP-ish way to accomplish something like this in rails is pretty easy; you could also roll your own Strategy, Adapter, or even a Builder pattern to do this.
But, there is some low hanging fruit, you can refactor your code so the common parts are less obtrusive -- this is a little better but,
create_events
is still verycase
'y: