迪米特法則(Law of Demeter),又稱最少知識原則,簡單說來就是 一個對象應該對其他對象有最少的了解。迪米特法則用于降低類與類之間的耦合,那么當其中某一個模塊發生修改時,就會盡量少地影響其他模塊,擴展會相對容易。
一句話概括下來,就是“只和朋友打交道,朋友的朋友不是朋友”,對于一個對象,其朋友包括以下幾類:
(1) 當前對象本身(self);
(2) 以參數形式傳入到當前對象方法中的對象;
(3) 當前對象的成員對象(依rails來說,assocation的屬于成員對象);
(4) 如果當前對象的成員對象是一個集合,那么集合中的元素也都是朋友;
(5) 當前對象所創建的對象。
舉一個例子
發布批時會更新產品信息價,在價格網quotation_batch.rb定義方法大致如下:
class QuotationBatch
def publish_prices_no_transaction(options={})
sql, arr = options[:publish_type] == :full ?
['', self.id] : [' and products.id in (?)',[self.id, options[:ids]]]
products_ids = Product.all :conditions => "some",:select => "id"
return 'true' if products_ids.blank?
products_ids.each_slice(1000) do |id_arr|
products = Product.all(:conditions => ['id in (?)', id_arr],
:include => [:all_product_prices])
products.each do |product|
raise ActiveRecord::Rollback unless product.publish_price(options[:user], self)
end
end
'true'
end
end
簡要說明一下: quotation_batch 是保存批的類;product_price是保存報價的類,字段batch_id保存批號,字段product_id保存產品號,last字段用于聲明是最新報價還是歷史報價(1為最新報價,3是歷史報價);product是產品類。代碼大致流程如下:
publish_prices_no_transaction 遍歷product,調用product的publish_price發布報價,而product再根據條件修改product_price狀態
代碼不太符合迪米特法則,product和quotation_batch之間不應該有關聯,初看代碼很是一頭霧水。
首先,真正發布報價的方法不應該定義在product中,而應該定義在product_price中,因為只有product_price和product和batch是朋友關系,那么,在publish_prices_no_transaction中應該遍歷product_price,而不是product
偽代碼如下
class ProductPrice
belongs_to :product
belongs_to :batch
def publish_price
#更新上一版報價狀態
self.prev_price.update_status
#使本次報價為最新報價
self.make_newst_price
...
end
end
class Product
has_many :product_prices
end
class QuotationBatch
has_many :product_prices
def publish_batch
self.product_prices.each do |product_price|
product_price.publish_price
end
#更新企業狀態等其他代碼
end
end
這樣改一下,邏輯就清晰了很多,看來在工作中還是要注意下設計原則滴~