【问题标题】:Rails AntiPatterns book - Doubts on compositionRails AntiPatterns 书 - 对组合的怀疑
【发布时间】:2012-01-25 09:50:17
【问题描述】:

我正在阅读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 = Order.new

然后通过做转换:

order.converter.to_pdf 
  • 为什么 OrderConverter 中需要 attr_reader :order 行?这样我们就可以从 OrderConverter 对象访问订单了吗?是否需要能够做到 order.converter.to_pdf ?没有那个 attr_reader 我们可以做到这一点,对吗?

【问题讨论】:

    标签: ruby-on-rails composition anti-patterns


    【解决方案1】:

    Order 的实例被传递给initialize 方法并存储为实例变量(使用@ 语法:@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
    

    【讨论】:

    • 杰夫,我相信即使不做 attr_reader 我们也可以从其他方法(在同一个类中)访问 Order 对象,对吧?我相信从任何转换器实例获取订单都是有用的。
    • 当然,这就是我从转换器内部添加它的原因,attr_reader 只是一个方便的访问器。但是如果没有attr_accessor :order,任何对converter.order 的调用都会引发“NoMethodError”。在此特定实例之外无法访问对订单的引用,因为实例变量具有...实例范围。
    • 抱歉,之前的评论有太多错别字/编辑:阅读attr_reader(只读),而不是attr_accessor(读写)。
    【解决方案2】:

    变量前面的@ 使其成为实例变量。如果它不存在,该变量将只是一个局部变量。我猜因为这是一本关于 Rails 的书,所以假设这段代码将在控制器中。控制器想要跨方法共享或在视图中公开的变量需要是实例变量。如果是这种情况,@order 可能是通过请求中的参数或从数据库中提取的值创建的。

    这可能不是那么重要,尽管他的示例和您的示例都有效 - 我认为作者只是展示了对 OrderConverter 的调用的外观,而忽略了 Order 对象的创建方式。

    attr_reader :orderOrderConverter 中为@order 实例变量创建一个“getter”方法——to_pdf 不需要它——它将用于将OrderOrderConverter 中取出converter.order。到目前为止,我认为您提供的代码中没有必要包含此功能,但以后可能需要它。

    【讨论】:

    • 感谢您的回答。我希望我能给出两个被接受的答案,它们都对我澄清这个概念有很大帮助。
    猜你喜欢
    • 1970-01-01
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多