命令,不要去询问 (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个关于这个原则的例子,都很有价值。

例一

不好:

1 <% if current_user.admin? %>
2   <%= current_user.admin_welcome_message %>
3 <% else %>
4   <%= current_user.user_welcome_message %>
5  
6 <% end %>

好:

1 <%= current_user.welcome_message %>

例二

不好:

1 def check_for_overheating(system_monitor)
2  
3   if system_monitor.temperature > 100
4     system_monitor.sound_alarms
5   end
6  
7 end

好:

01 system_monitor.check_for_overheating
02  
03 class SystemMonitor
04   def check_for_overheating
05  
06     if temperature > 100
07       sound_alarms
08     end
09   end
10  
11 end

例三

不好:

1 class Post
2   def send_to_feed
3  
4     if user.is_a?(TwitterUser)
5       user.send_to_feed(contents)
6     end
7  
8   end
9 end

好:

01 class Post
02   def send_to_feed
03  
04     user.send_to_feed(contents)
05   end
06 end
07  
08 class TwitterUser
09   def send_to_feed(contents)
10  
11     twitter_client.post_to_feed(contents)
12   end
13 end
14  
15 class EmailUser
16   def send_to_feed(contents)
17  
18     # no-op.
19   end
20 end

例四

不好:

1 def street_name(user)
2  
3   if user.address
4     user.address.street_name
5   else
6  
7     'No street name on file'
8   end
9 end

好:

01 def street_name(user)
02  
03   user.address.street_name
04 end
05  
06 class User
07   def address
08  
09     @address || NullAddress.new
10   end
11 end
12  
13 class NullAddress
14  
15   def street_name
16     'No street name on file'
17   end
18 end

好的面向对象编程是告诉对象你要做什么,而不是询问对象的状态后根据状态做行动。数据和依赖这些数据的操作都应该属于同一个对象。

命令,不要去询问!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>