富model,瘦controller

本文探讨了如何优化MVC架构中的控制器与模型部分,通过将业务逻辑从视图转移至控制器,并进一步提炼至模型,实现了代码的清晰划分,提高了系统的可读性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很久以前看过的一篇文章。挺简单,不过这种思想很重要。简单的复述,也不能完全算翻译。
 
----先看这么一段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| %> 
    <div id="person-<%= person.new_record? ? "new" : person.id %>"> 
        <span class="name"> 
            <%= person.last_name %>, <%= person.first_name %> 
        </span> 
        <span class="age"> 
            <%= (Date.today - person.birthdate) / 365 %> 
        </span> 
    </div> 
<% end %>
再看看controller和model里的东西:
# app/controllers/people_controller.rb 
class PeopleController < ActionController::Base 
end 

# app/models/person.rb 
class Person < ActiveRecord::Base 
    has_one :address 
end
空荡荡的controller,而在model里仅仅有一句关系声明。这么组合成的MVC显得很别扭,似乎就是一层渲染模板。几乎把C与M都忽略了。

无论如何这在MVC框架里是糟糕透顶的现象,MVC经过这么多年的实践考验,它的优点在于“可读性强”“可维护性好”“模块化”“关注点的分离”等等,我想你用MVC框架也就是想实现这些优点哇?那么首先需要改进的是尽可能的将逻辑内容搬到controller中,controller的作用就是介于view和model之间,起到一个类似中介的作用。下面来看下这样改动之后的代码:
<!-- app/views/people/index.rhtml --> 
<% @people.each do |person| %> 
    <div id="person-<%= person.new_record? ? "new" : person.id %>"> 
        <span class="name"> 
            <%= person.last_name %>, <%= person.first_name %> 
        </span> 
        <span class="age"> 
            <%= (Date.today - person.birthdate) / 365 %> 
        </span> 
    </div> 
<% end %>
# app/controllers/people_controller.rb 
class PeopleController < ActionController::Base 
    def index 
        @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 < ActiveRecord::Base 
    # ... 

    def name 
        "#{last_name}, #{first_name}" 
    end 

    def age 
        (Date.today - person.birthdate) / 365 
    end 

    def pseudo_id 
        new_record? ? "new" : id 
    end 
end
<!-- app/views/people/index.rhtml --> 
<% @people.each do |person| %> 
    <div id="person-<%= person.pseudo_id %>"> 
        <span class="name"><%= person.name %></span> 
        <span class="age"><%= person.age %></span> 
    </div> 
<% end %>
这样通过在model中添加几个虚拟属性,在view里调用,显得很合理,而且模板代码更简洁明了了。
 
下一步就是将controller里的代码理一理。因为controller只能算是个中介,不应该参与很多的逻辑处理。
# app/models/person.rb 
class Person < ActiveRecord::Base 
    def self.find_recent 
        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 < ActionController::Base 
    def index 
        @people = Person.find_recent 
    end 
end
现在看index这个action,扫一眼就知道它要干吗。而且如果find_recent方法在以后需要改变时,可以直接在model里进行修改。
 
--总结一下,尽量使得controller的actions中的代码和view中的代码更少,在action中要是能只写一行达到效果最好。在view中要尽量使代码贴近html结构。
 
还有一个不太明显的好处就是,瘦action可以使得  respond_to 结构更突出,可以看出输出的类型是什么。
class PeopleController < ActionController::Base 
    def index 
        @people = Person.find_recent 

        respond_to do |format| 
            format.html 
            format.xml { render :xml => @people.to_xml(:root => "people") } 
            format.rss { render :action => "index.rxml" } 
        end 
    end 
end




本文转自 fsjoy1983 51CTO博客,原文链接:http://blog.51cto.com/fsjoy/121947,如需转载请自行联系原作者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值