假设我编写了一个gem,它会对Google Distance API进行惰性调用并使结果可用。像这样:
module GoogleDirections
class Journey
attr_reader :directions, :origin, :destination
# Origin and destination can either be string addresses or
# pairs of lat,long co-ordinates
def initialize(origin, destination)
@origin = origin.is_a?(Array) ? origin.join(',') : origin
@destination = destination.is_a?(Array) ? destination.join(',') : destination
end
# calculate the trip distance
def trip_distance
@trip_distance ||= directions.inject(0){|sum,leg| sum += leg["distance"]["value"] }
end
# This method requests directions from Google when we need to
def directions
@directions ||= JSON.parse(# get the directions from )
end
end
end
所以,现在我在我的Rails项目中添加这个gem。 Tis rails项目有总线和目的地的公共汽车。所以我想要做的是在保存到数据库的路线之前向谷歌查询路线。
class Bus < ActiveRecord::Base
before_save :set_trip_distance
def set_trip_distance
self.trip_distance = GoogleDirections::Journey.new(self.origin, self.destination).trip_distance
end
end
但是如果我在我的宝石中添加一个行程持续时间方法,我可能最终也会在我的总线模型上设置它。显然,如果我这样做,我应该提取一个Journey实例的创建。
class Bus < ActiveRecord::Base
before_save :set_trip_distance, :set_trip_duration
def journey
GoogleDirections::Journey.new(self.origin, self.destination)
end
def set_trip_distance
self.trip_distance = journey.trip_distance
end
def set_trip_duration
self.trip_duration = journey.trip_duration
end
end
但set_trip_distance
和set_trip_duration
方法似乎彼此非常相似。我可以想象一下我可能在公交车上设置6种不同的路线属性。这让我觉得我必须有一个更好的设计模式。
我想我可以设计Gem,我可以include
它,但这样做会增加Gem和我的公共汽车上的列名之间的耦合,这看起来很糟糕?
什么是最佳选择?
答案 0 :(得分:0)
如果您想让用户有机会为Journey
数据命名自己的列,那就是他们必须做的事情。
但是,如果已经有了一段旅程,为什么不把它作为一个关联,或者在一些元编程下进行包装呢?
class Bus < ActiveRecord::Base
has_journey :journey
# Could define journey origin/dest in terms of Bus fields:
has_journey :journey, :origin => :starting_loc, :destination => :ending_loc
end
那就是说,取决于你实际实施的是什么,看起来更像是一辆公共汽车将有多次旅行,除非它是一次性公共汽车。这将允许一些有趣的东西,如预定的日记,旅程历史等。
class Bus < ActiveRecord::Base
has_journeys
end