命令,不要去詢問 (Tell, Don’t Ask)
前些時間我曾經翻譯過一篇叫做《這里我說了算!》的文章,里面作者講述了關于“命令,不要去詢問(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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!