1

私はいくつかのモデルを持っており、次のようなビューコードを持っています

class Address < ActiveRecord::Base
  belongs_to :customer
end

class Customer < ActiveRecord::Base
  has_one :address
  has_many :invoices
end

class Invoice < ActiveRecord::Base
  belongs_to :customer
end

このコードは、単一の住所を持つ顧客の単純な請求書構造を示しています。請求書の住所行を表示するためのビューコードは次のようになります。

<%= @invoice.customer.name %>
<%= @invoice.customer.address.street %>
<%= @invoice.customer.address.city %>,
<%= @invoice.customer.address.state %>
<%= @invoice.customer.address.zip_code %>

上記のビューコードは理想的ではありません。適切にカプセル化するために、請求書は顧客オブジェクトを越えて住所オブジェクトのストリート属性に到達しないようにする必要があります。たとえば、将来、顧客が請求先住所と配送先住所の両方を持つようにアプリケーションを変更した場合、これらのオブジェクトを越えて通りを取得するためにコード内のすべての場所が壊れ、変更する必要があります。この問題を回避するにはどうすればよいですか?

4

3 に答える 3

2

簡単な解決策は、顧客がメインアドレスを返すメソッドを持っていることです。

class Customer < ActiveRecord::Base
  def main_address
    self.address
  end
end

この方法でのみアドレスにアクセスする場合、複数のアドレスがある場合は、main_addressメソッドを変更するだけで、やりたいことができます。

編集1:

別のオプションは、@soundarによって提案されたデリゲートを使用することです

class Invoice < ActiveRecord::Base
  belongs_to :customer
  delegate :address, :to => :customer
end
于 2012-10-29T12:48:19.520 に答える
0

デリゲート機能を使用して、関数呼び出しのシーケンスを減らすことができます。

class Invoice < ActiveRecord::Base
  belongs_to :customer
  delegate :address, :to => :customer
end

<%= @invoice.customer.name %>
<%= @invoice.address.street %>
<%= @invoice.address.city %>,
<%= @invoice.address.state %>
<%= @invoice.address.zip_code %>
于 2012-10-29T13:19:29.417 に答える
0

説明するだけの問題を回避するには、をフォローすることが重要です。これはLaw of Demeter、とも呼ばれますPrinciple of Least Knowledge

デメテルの法則に従うには、上記のコードを次のように書き直すことができます。

class Address < ActiveRecord::Base
  belongs_to :customer
end

class Customer < ActiveRecord::Base
  has_one :address
  has_many :invoices

  def street
    address.street
  end

  def city
    address.city
  end

  def state
    address.state
  end

end

class Invoice < ActiveRecord::Base
  belongs_to :customer

  def customer_name
    customer.name
  end

  def customer_street
    customer.street
  end

  def customer_state
    customer.state
  end
end

また、ビューコードを次のように変更できます。

<%= @invoice.customer_name %>
<%= @invoice.customer_street %>
<%= @invoice.customer_city %>
<%= @invoice.customer_state %>

上記のコードでは、請求書のパブリックインターフェイスは、請求書の残りのインターフェイスとはほぼ関係のないメソッドによって汚染されています。これはデメテルの法則の一般的な欠点であり、RubyonRailsに特に固有のものではありません。

現在、このメソッドはクラスレベルのdelegateメソッドです。このメソッドは、オブジェクト上に作成される1つ以上のメソッドが実際に関連オブジェクトによって提供されることを示すためのショートカットを提供します。このデリゲートメソッドを使用すると、次のように例を書き直すことができます。

class Address < ActiveRecord::Base
  belongs_to :customer
end

class Customer < ActiveRecord::Base
  has_one :address
  has_many :invoices

  delegate :street, :city, :state, :to => :address
end

class Invoice < ActiveRecord::Base
  belongs_to :customer

  delegate :name, :street, :city, :state, :to => :customer, :prefix => true
end

この状況では、ビューコードを変更する必要はありません。メソッドは、以前と同じように公開されます。

<%= @invoice.customer_name %>
<%= @invoice.customer_street %>
<%= @invoice.customer_city %>
<%= @invoice.customer_state %>
于 2012-10-30T06:32:15.887 に答える