从这一集开始,我们一起探讨一下关于重构的话题。重构是指在不改变软件功能的前提下对代码进行优化,以达到去除冗余代码、提高代码可读性及可维护性的的目的。
下面页面是一个用户列表,点击用户名后显示用户资料。需要注意的是,有些用户有中间名(middle name)有些则没有。
![列表页和用户资料页 列表页和用户资料页](https://i-blog.csdnimg.cn/blog_migrate/d24d7dce4283f834b7ad565f826fd076.png)
浏览器中显示的列表页及用户资料页.
先看看列表页的代码:
ruby
<h1>Users</h1>
<ul>
<% for user in @users %>
<li>
<a href="<%= user_path(user) %>">
<%= user.first_name %>
<%= "#{user.middle_initial}." unless user.middle_initial.nil? %>
<%= user.last_name %>
</a>
</li>
<% end %>
</ul>
列表页代码
上面的代码先是获取所有的用户对象,进行循环。<a>标签中的三行代码用来显示用户名。接下来,是用户资料页面:
ruby
<h1>Profile</h1>
<p>
Name:
<%= @user.first_name %>
<%= "#{@user.middle_initial}." unless @user.middle_initial.nil? %>
<%= @user.last_name %>
</p>
<%= link_to 'Users List', users_path %>
用户资料页代码
用户资料页面和列表页一样,也用三行代码显示用户名。很明显做了重复的工作,这里便成为我们的优化点。分析一下代码,其中第一行和第三行分别显示名称和姓氏;第二行是当有中间名时显示外加一个点,没有中间名的时候什么都不显示。
如何开始这次重构?
可以把这个通用逻辑抽取到一个工具方法中,但我觉得这三行逻辑与User
模型的关联更紧密些。所以应该将它们抽取到模型中更加合理。在User
类中增加一个名为full_name
的方法.将页面中的代码移动到这个方法中,给一个局部变量赋值并返回。
ruby
class User < ActiveRecord::Base
def full_name
name = first_name + ' '
name += "#{middle_initial}. " unless middle_initial.nil?
name += last_name
name
end
end
增加了full_name
方法的User
类
直接将代码拷贝到这里肯定是行不通的,@user
变量在User
类中不存在。我们需要把它去掉,因为这是一个实例方法,当前操作的对象就是这个用户本身。
检查重构是否正确。
该在页面中调用full_name
方法来替代之前的那三行代码。下面是修改后的列表页面代码。
ruby
<a href="<%= user_path(user) %>">
<%= user.full_name %>
</a>
使用full_name
的列表页面代码。
代码依然还有提升的空间,创建超链接的<a>标签使用起来太麻烦,可以被Rails提供的link_to
方法替代。
ruby
<%= link_to user.full_name, user_path(user) %>
使用了link_to
方法的列表页面。
这样一来,页面代码是否变得清爽多了?我们去掉了冗余代码,又把本应该由模型负责的逻辑移到适当的位置。其实还有优化的余地,且听下回分解。
重构之后的代码
ruby
class User < ActiveRecord::Base
def full_name
name = first_name + ' '
name += "#{middle_initial}. " unless middle_initial.nil?
name += last_name
name
end
end
重构后的User
类。
ruby
<h1>Users</h1>
<ul>
<% for user in @users %>
<li><%= link_to user.full_name %></li>
<% end %>
</ul>
重构后的列表页(index
)。
ruby
<h1>Profile</h1>
<p>Name: <%= @user.full_name %></p>
<%= link_to 'Users List', users_path %>
重构后的用户资料页(show
)。
转自:http://railscasts.com/episodes/10-refactoring-user-name-part-1?language=zh&view=asciicast