[DAY3] MVC与散落各处的逻辑

上回说到 Fat Model 的逻辑散落在各处,那这回就要来说说散落在哪、以及造成这种现象的原因。

Rails 的 MVC

MVC(Model–View–Controller)是一种软件架构,主要是将软件系统分成三个部分,使得程序分工容易,利於团队的扩张。

更多关於 MVC 的文章可以参考以下
Model、View、Controller 三分天下

接着我们看看 Rails 官网的教学,以下是显示一篇文章的 model、controller 跟 view。

Model

class Article < ActiveRecord::Base
end

Controller

class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])
  end
end

View

<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 中取用

Controller

class ArticlesController < ApplicationController
  def show
    @article_count = Article.count
    @article = Article.find(params[:id])
  end
end

View

<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 中。

Model

class Article < ActiveRecord::Base
	def display_title
		"#{count}. #{title}" 
	end
end

View

<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 便有了耦合 /images/emoticon/emoticon20.gif

随着专案越来越大,view 中会参杂许多逻辑,加上 model 和 model 间也会有许多的关联,久而久之便会变成一坨大泥球。

後记

在 Rails 中提出的解决方法是透过 presenter 这个设计模式去解决这个问题,所有的显示逻辑应该被包在 presenter 中而不是在 model 上,model 不应该知道 view 的存在,不过如何实作也是需要好好设计!

下一篇会分享 Rails 预设的资料夹结构如何加重这个问题 /images/emoticon/emoticon08.gif


<<:  Day06 - 端到端(end-to-end)语音辨识-CTC part 2

>>:  Day 6 Dart语言-变数与常数

Day 2 公告吧!

当我们浏览着一列列毫无止尽的文字,不知道该如何心安的情况下... 网路的世界本来就是犹如沙子般繁多的...

IOS 菜菜菜鸟30天挑战 Day-30 结语+转图小技巧

我实在没想到我能坚持连续30天不间断发文,对我来说真的是一大挑战,因为我不是一个经得起坚持的人,这次...

到底你想当主管吗?

我们定义了管理者主要的工作(what),在作更深入讨论 how 之前,我希望能引导你与自己有个诚实...

Day 14 -资料查询语言 LIKE !

LIKE 运算子搭配 WHERE 子句可以依一特定模式 (Pattern) 为条件来搜寻资料表中的特...

[Day 19] 针对网页的单元测试(五)

再写登入的验证及功能 今天我们要来做登入的判断跟动作, 我们在HomeController.php引...