2010年8月25日 星期三

富model,瘦controller

富model,瘦controller - 李驥平

很久以前看過的一篇文章。挺簡單,不過這種思想很重要。簡單的複述,也不能完全算翻譯。
----先看這麼一段rhtml代碼:渲染模板中加入了這麼多的邏輯,看起來不倫不類,這麼做行是行,但是缺點很多,新手一般有這個毛病。那麼這樣做,首先是可讀性很差,因為在渲染代碼中最好都是貼近HTML代碼,而這堆代碼裡把C的內容也加進來了。
<% people = Person.find( :conditions => ["added_at > ? and deleted = ?", Time.now.utc, false],
:order => "last_name, first_name") %>
<% people.reject { |p| p.address.nil? }.each do |person| %>
">

<%= person.last_name %>, <%= person.first_name %>


<%= (Date.today - person.birthdate) / 365 %>


<% end %>
再看看controller和model裡的東西:
# app/controllers/people_controller.rb
class PeopleController <>
空蕩蕩的controller,而在model裡僅僅有一句關係聲明。這麼組合成的MVC顯得很彆扭,似乎就是一層渲染模板。幾乎把C與M都忽略了。

無論如何這在MVC框架裡是糟糕透頂的現象,MVC經過這麼多年的實踐考驗,它的優點在於「可讀性強」「可維護性好」「模塊化」「關注 點的分離」等等,我想你用MVC框架也就是想實現這些優點哇?那麼首先需要改進的是儘可能的將邏輯內容搬到controller中,controller 的作用就是介於view和model之間,起到一個類似中介的作用。下面來看下這樣改動之後的代碼:

<% @people.each do |person| %>
">

<%= person.last_name %>, <%= person.first_name %>


<%= (Date.today - person.birthdate) / 365 %>


<% end %>
# app/controllers/people_controller.rb
class PeopleController < people =" Person.find(" conditions =""> ["added_at > ? and deleted = ?", Time.now.utc, false],
:order => "last_name, first_name")
@people = @people.reject { |p| p.address.nil? }
end
end
這樣看起來就好多了,模板中的代碼更像是HTML的結構,而且你粗略的看一下controller裡的代碼就能知道在這個action渲染的模板中會顯示什麼數據。
還可以更進一步做的事情就是將現在模板代碼中關於一部分數據的處理挪到Model中來:
# app/models/person.rb
class Person <>

<% @people.each do |person| %>
">
<%= person.name %>
<%= person.age %>

<% end %>
這樣通過在model中添加幾個虛擬屬性,在view裡調用,顯得很合理,而且模板代碼更簡潔明了了。
下一步就是將controller裡的代碼理一理。因為controller只能算是個中介,不應該參與很多的邏輯處理。
# app/models/person.rb
class Person < people =" find(" conditions =""> ["added_at > ? and deleted = ?", Time.now.utc, false],
:order => "last_name, first_name")
people.reject { |p| p.address.nil? }
end

# ...
end

# app/controllers/people_controller.rb
class PeopleController < people =" Person.find_recent">
現在看index這個action,掃一眼就知道它要干嗎。而且如果find_recent方法在以後需要改變時,可以直接在model裡進行修改。
--總結一下,儘量使得controller的actions中的代碼和view中的代碼更少,在action中要是能只寫一行達到效果最好。在view中要儘量使代碼貼近html結構。
還有一個不太明顯的好處就是,瘦action可以使得 respond_to 結構更突出,可以看出輸出的類型是什麼。
class PeopleController < people =" Person.find_recent" xml =""> @people.to_xml(:root => "people") }
format.rss { render :action => "index.rxml" }
end
end
end