Demeter法则视图:创建委托来访问相关对象的属性吗?

时间:2013-06-01 03:34:12

标签: ruby-on-rails oop law-of-demeter

德米特定律似乎是一个非常强大的概念。我可以理解它如何帮助编写良好且可维护的面向对象的代码。

Some people suggest每次需要访问视图中关联对象的属性时编写委托方法。而不是在视图中写这样的东西

@order.customer.name

你会写这段代码:

# model
class Order < ActiveRecord::Base
  belongs_to :customer
  delegate :name, :to => :customer, :prefix => true
end

#view
@order.customer_name

另一方面,people argue that you views should not dictate models and you should not add methods such as delegate to a model only for the sake of trading a dot for an underscore in a view

在视图中违反Demeter法则,在模型中编写委托方法是否被认为是最佳做法?

1 个答案:

答案 0 :(得分:7)

我将您的customer_name自动生成的委托方法视为现在正在运行的最简单的事情。由于它是一个方法调用(而不是一系列方法链),因此以后很容易重构(或者比某些链式方法更容易重构)

想象一下,无论出于何种原因,都会向订单中添加许多客户,其中一个客户是主要客户。现在您的订单类可能看起来像

class Order < ActiveRecord::Base

  has_many :customers

  def customer_name
    if customers.first.primary?
      customers.first.name
    else
      customers.last.name
    end
end

很容易用我们自己的方法替换那个方便委托生成的方法。

(第一次编写也非常容易,因为delegate会处理所有样板文件。你很可能会永远在你的应用程序中使用这种形式的customer_name。这很难知道。但是第一次轻松/自动编写的代码丢弃很便宜:))

当然,您必须避免编写customer_streetaddress_is_united_states?等方法名称的情况(是的,而不是以下划线编码对象图,而是用下划线编码它。)

如果您的视图确实需要知道用户是否位于美国,那么这样的方法可能会有效:

class Order < ActiveRecord::Base

    belongs_to :customer

    def shipping_to_us?
      customer.shipping_country == "USA"
      # Law of Demeter violation would be:
      # customer.addresses.first.country == "USA"
    end
  end

  class Customer < ActiveRecord::Base
    has_many :addresses

    def shipping_country
      addresses.first.country
    end
  end

请注意Order 如何 {/ 1}}对象的送货地址,而告诉客户获取客户的第一个地址的国家/地区。就像一个告诉你做某事的老板,让你独自与老板一样,微观管理你日常工作的方式。 (有关额外的启发,请阅读问题,不要告诉Ruby开发方法:))

有一些关于使用演示者,装饰器方法或帮助器的内容,以避免让这个可能只显示逻辑代码乱丢你的模型。我将把它作为练习留给读者:)