我正在阅读Rails AntiPatterns书,我很享受。在某一点上,作者谈到了合成的优点,并给出了一个例子,其中 Order 类赋予转换(到其他格式)到另一个类的责任,称为 OrderConverter 。这些类定义为:
class Order < ActiveRecord::Base
def converter
OrderConverter.new(self)
end
end
class OrderConverter
attr_reader :order
def initialize(order)
@order = order
end
def to_xml
# ...
end
def to_json
# ...
end
...
end
然后作者说:“通过这种方式,您可以将转换方法放在一个单独且易于测试的类中。转换订单的PDF版本现在只需要调用以下内容:“
@order.converter.to_pdf
关于这一点,我的问题是:
为什么您认为订单对象前面有@?不应该创建为:
order = Order.new
然后转换:
order.converter.to_pdf
attr_reader :order
行?我们可以从 OrderConverter 对象访问订单吗?是否需要能够做到
order.converter.to_pdf
?如果没有 attr_reader ,我们可以做到这一点吗?答案 0 :(得分:2)
变量前面的@
使其成为实例变量。如果它不存在,变量就只是一个局部变量。我猜这是因为这是一本关于Rails的书,它假设这段代码在控制器中。控制器希望跨方法共享或在其视图中公开的变量需要是实例变量。如果是这种情况,@order
可能是通过请求中的参数或从数据库中提取的值创建的。
这可能不是那么重要,他的例子和你的例子都有用 - 我认为作者只是展示了对OrderConverter
的调用是什么样的,并忽略了Order
对象的方式得到了。
attr_reader :order
为@order
中的OrderConverter
实例变量创建了一个“getter”方法 - to_pdf
不需要它 - 它将用于获取{{1}通过Order
退出OrderConverter
。我认为到目前为止您没有需要在代码中使用此代码,但可能稍后需要它。
答案 1 :(得分:2)
将Order
的实例传递给initialize
方法并存储为实例变量(使用@ syntax:@order
)。这样,可以从转换器中的其他方法访问此变量(该变量具有实例范围):
class OrderConverter
def to_pdf
@order.items.each do |item|
# Write the order items to the PDF
end
end
end
attr_reader不是严格要求的,但是从其他方法访问Order对象的便捷方式:
class OrderConverter
def to_pdf
order.items.each do |item|
# Write the order items to the PDF
end
end
end
它还允许您从任何转换器实例中获取对订单的引用:
converter.order