命令,不要去詢問 (Tell, Don’t Ask)

openkk 12年前發布 | 6K 次閱讀 編程

前些時間我曾經翻譯過一篇叫做《這里我說了算!》的文章,里面作者講述了關于“命令,不要去詢問(Tell, Don’t Ask)”原則:

我看到的最多被違反的原則是“命令,不要去詢問(Tell, Don’t Ask)”原則。這個原則講的是,一個對象應該命令其它對象該做什么,而不是去查詢其它對象的狀態來決定做什么(查詢其它對象的狀態來決定做什么也被稱作 ‘功能嫉妒(Feature Envy)’)。

這篇文章里有個很生動的例子,我至今記憶猶新:

if (person.getAddress().getCountry() == “Australia”) {

這違反了得墨忒耳定律,因為這個調用者跟Person過于親密。它知道Person里有一個Address,而Address里還有一個country。它實際上應該寫成這樣:

if (person.livesIn(“Australia”)) {

非常的明了。今天我又看到一個關于“Tell, Don’t Ask”原則的文章,里面提供了4個關于這個原則的例子,都很有價值。

例一

不好:

<% if current_user.admin? %>
  <%= current_user.admin_welcome_message %>
<% else %>
  <%= current_user.user_welcome_message %>

<% end %>

好:

<%= current_user.welcome_message %>

例二

不好:

def check_for_overheating(system_monitor)

  if system_monitor.temperature > 100
    system_monitor.sound_alarms
  end

end

好:

system_monitor.check_for_overheating

class SystemMonitor
  def check_for_overheating

    if temperature > 100
      sound_alarms
    end
  end

end

例三

不好:

class Post
  def send_to_feed

    if user.is_a?(推terUser)
      user.send_to_feed(contents)
    end

  end
end

好:

class Post
  def send_to_feed

    user.send_to_feed(contents)
  end
end

class 推terUser
  def send_to_feed(contents)

    推ter_client.post_to_feed(contents)
  end
end

class EmailUser
  def send_to_feed(contents)

    # no-op.
  end
end

例四

不好:

def street_name(user)

  if user.address
    user.address.street_name
  else

    'No street name on file'
  end
end

好:

def street_name(user)

  user.address.street_name
end

class User
  def address

    @address || NullAddress.new
  end
end

class NullAddress

  def street_name
    'No street name on file'
  end
end

好的面向對象編程是告訴對象你要做什么,而不是詢問對象的狀態后根據狀態做行動。數據和依賴這些數據的操作都應該屬于同一個對象。

命令,不要去詢問!

[本文英文原文鏈接:Tell, Don’t Ask / 譯文:外刊IT評論]

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!