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

mig*_*igu 7 oop ruby-on-rails law-of-demeter

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

有些人建议每次需要访问视图中关联对象的属性时编写委托方法.而不是在视图中写这样的东西

@order.customer.name
Run Code Online (Sandbox Code Playgroud)

你会写这段代码:

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

#view
@order.customer_name
Run Code Online (Sandbox Code Playgroud)

另一方面,人们认为你的观点不应该指示模型,你不应该只为了在视图中交换下划线的点而向模型添加委托等方法.

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

Rya*_*cox 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
Run Code Online (Sandbox Code Playgroud)

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

(第一次编写它也非常容易,因为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
Run Code Online (Sandbox Code Playgroud)

注意这里是如何Order 要求Customer对象的送货地址,VS 告诉客户得到它的客户的首地址的国家.就像一个告诉你做某事的老板,让你独自与老板一样,微观管理你日常工作的方式.(有关额外的启发,请阅读问题,不要告诉Ruby开发的方法:))

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