上回说到 Fat Model 的逻辑散落在各处,那这回就要来说说散落在哪、以及造成这种现象的原因。
MVC(Model–View–Controller)是一种软件架构,主要是将软件系统分成三个部分,使得程序分工容易,利於团队的扩张。
更多关於 MVC 的文章可以参考以下
Model、View、Controller 三分天下
接着我们看看 Rails 官网的教学,以下是显示一篇文章的 model、controller 跟 view。
class Article < ActiveRecord::Base
end
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id])
end
end
<h1>Listing articles</h1>
<table>
<tr>
<th>Title</th>
<th>Text</th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
</tr>
<% end %>
</table>
写起来很方便快速,但却有个致命的问题,在 view 中可以直接拿到 model
接着我们加入一些情境,加速程序腐化的速度
假设现在收到一个需求是想要计算文章的数量,并跟着文章标题一起显示,而且2个小时後就需要 demo!
最快的做法是在 controller 上新增这个逻辑并在 view 中取用
class ArticlesController < ApplicationController
def show
@article_count = Article.count
@article = Article.find(params[:id])
end
end
<h1>Listing articles</h1>
<table>
<tr>
<th>Title</th>
<th>Text</th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= "#{@article_count}. #{article.title}" %></td>
<td><%= article.text %></td>
</tr>
<% end %>
</table>
这时候会衍生两个问题,第一个是如果很多不同的 view 都会使用这个逻辑,这段 code 必须复制过去,违反 DRY 原则,第二个是如果显示上有许多这样的调整,controller 上会有许多逻辑,instance variable 也会无止境的扩张。
接下来可能会想要把 controller 上的逻辑收进 model 中。
class Article < ActiveRecord::Base
def display_title
"#{count}. #{title}"
end
end
<h1>Listing articles</h1>
<table>
<tr>
<th>Title</th>
<th>Text</th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= article.display_title %></td>
<td><%= article.text %></td>
</tr>
<% end %>
</table>
於是 model 和 view 便有了耦合
随着专案越来越大,view 中会参杂许多逻辑,加上 model 和 model 间也会有许多的关联,久而久之便会变成一坨大泥球。
在 Rails 中提出的解决方法是透过 presenter 这个设计模式去解决这个问题,所有的显示逻辑应该被包在 presenter 中而不是在 model 上,model 不应该知道 view 的存在,不过如何实作也是需要好好设计!
下一篇会分享 Rails 预设的资料夹结构如何加重这个问题
<<: Day06 - 端到端(end-to-end)语音辨识-CTC part 2
当我们浏览着一列列毫无止尽的文字,不知道该如何心安的情况下... 网路的世界本来就是犹如沙子般繁多的...
我实在没想到我能坚持连续30天不间断发文,对我来说真的是一大挑战,因为我不是一个经得起坚持的人,这次...
我们定义了管理者主要的工作(what),在作更深入讨论 how 之前,我希望能引导你与自己有个诚实...
LIKE 运算子搭配 WHERE 子句可以依一特定模式 (Pattern) 为条件来搜寻资料表中的特...
再写登入的验证及功能 今天我们要来做登入的判断跟动作, 我们在HomeController.php引...