iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 19
0

MVC 開發架構

MVC,如果你開始學後端工程,或是任意程式語言,
一定會碰到的一個技術名詞。
街頭上一大堆號稱 MVC 的框架,
丟 Google 也會查到許多 MVC 的介紹以及討論,
那 MVC 到底是什麼?

由於 MVC 有一些定義的爭論,
因此這篇的結論,筆者是參考大量說法,
以及根據過去開發的經驗觀察認知。

什麼是 MVC

MVC 是一種『網站開發架構』的技術名詞,
在一般網站的開發過程中,如果沒有任何的架構,
而是需求要什麼就寫什麼,設計畫什麼就寫什麼,
到最後,會留下一堆所謂的『技術債』,
讓你未來每次的更動,都要花更久的時間完成,
或是有很多隱藏的 Bug ,都是很可怕的東西。

而 MVC 就是設定一個基礎的架構,
未來每個開發者就依循這個架構去開發,
雖然淺扯到的區塊可能比較多,
但長期來看,維護性更佳,且能讓程式碼的『分工性』更加明確。

MVC 可以被分成三塊,Model, View, Controller
他們之間的關係和流程就像這張圖:
https://ithelp.ithome.com.tw/upload/images/20181102/20107758q0m1csOcm1.png

接下來我們會一一介紹,這三塊分別代表什麼意義!

View

view,是所謂的樣板、模板,
在網站裡常常以一般人常見的 HTML 方式撰寫,
寫起來就會像這樣:

// index.html
<div>
	<span>John</span>
	<span>18</span>
	<span>2018-09-10</span>
</dvi>
<div>
	<span>Tom</span>
	<span>29</span>
	<span>2018-09-03</span>
</div>

view 的任務,就是顯示畫面給使用者,
一個網站會有一大堆的 view,
畢竟常規上來說,幾乎就是一個網頁一個 view 的檔案。
上面的程式碼中,顯示了兩筆資料給使用者看,
但是直接把資料寫死很蠢,
所以我們在 RoR 中會這樣寫:

// index.html.erb

<% @users.each do | u | %>
<div>
	<span><%= u.name %></span>
	<span><%= u.age %></span>
	<span><%= u.date %></span>
</dvi>
<% end %>

@users 是一個陣列,裡面裝有所有的 user 資料,
這其實就是一個另類的『迴圈』,用作『 一筆一筆 』撈出 @users 裡面所有的資料,
但是這個變數來自 controller ,因此需要包在 <%%>符號之間,
畢竟這個檔案不是 html ,而是 html.erb 檔案,
erb 是讓 html 可以讀取 ruby 變數的副檔名。
而在每個 的標籤內,就改包在 <%= %>,因為這樣才能顯示變數內的資料。

這個檔案最後的輸出結果,就會像一開始上面的 HTML 檔案一般,
具有兩筆資料,以 HTML 的方式顯示。
這就是 view 的功能,和它與 controller 合作的方式。

Controller

Controller,他的任務是處理使用者的請求,
確定要讀取哪些資料,做好運算,並找出樣板,
確定要用 view,或是像是一個『 API 』,
只輸出資料,沒有 view。

在 Ruby 裡,一個典型 controller 會如下:

class UserController < ApplicationController
	def index
	    @users = User.all
	    @users_length = User.all.length
	    @classes = Class.where(id: 10)
	end
end

各位可以觀察到 def - index 內,
@users 就是上面 view 用到的變數,
他就是在 controller 裡面設定好,才能顯示在 view 中,
而這個 def 我們通常會稱呼為『action 』,
慣例上來說,我們會把 action 和對應到的 view 命名為同一個名稱,
這樣就很清楚的知道 index 這個 action 會去找 index.html 這個 view。
預設上來說,就是以 html 的方式顯現。

再來,如果我們的這個 action 想像 API 一樣,
只把資料輸出為 json 格式,
可以改成這樣寫:

class  UserController < ApplicationController
	def index
	    @users = User.all
	    @users_length = User.all.length
	    @classes = Class.where(id: 10)
	
	render json: { users: @users }
	end
end

使用 render 這個詞句,設定說我們顯示的模式為 json ,
那會有的資料就是 @users。
顯示起來就會像附圖這樣:
https://ithelp.ithome.com.tw/upload/images/20181102/20107758eFFYkPqcg1.png

因此 controller 的任務是比較『架構性』、『規畫性』。

在程式碼中,相信大家有注意到大寫的 User 和 Classes,
這個東西就是所謂的 『Model 』

Model

首先要先提的是,什麼是 Model,
Model 是資料的『容器』,不是『資料庫』,
這個概念要切的非常清楚喔!

我們程式從資料庫『取出資料』,
並放在 Model 內,讓 Controller 可以使用。
因此 Model 內裝資料的欄位,
和資料庫的欄位『不一定完全吻合』。

雖然在大部分的程式語言和框架,
都會預設 Model 內的欄位會和資料庫的欄位相同,
不過有時候可能會針對欄位內的資料做『預處理』,
例如,資料庫裡某筆資料的『價格』欄位是 100 塊,然後以美金計價,
但是我們網站要根據不同語系,轉換幣種,
台幣如果還是顯示 100 塊,會發生被刷單刷爆然後上 Ptt,記者再來抄新聞之類的,
因此會在取出資料時,預先把價格先乘上台幣的匯率,
之後在每次操作時都會拿到屬於該幣種的資料,
這才是 Model 真正的任務,『定義資料的內容』

而程式裡的 Model 通常會和資料庫欄位同名,
只是使用大寫開頭,並用單數命名方式。

#user.rb
class User < ApplicationRecord

end

可以內容什麼都不寫,那就是預設按照資料庫欄位的資料處理。

使用方法就像 controller 部分展示的一樣,直接呼叫 Model 。

@user = User.all
@classes = Class.where(id: 10)

這邊讀者會注意到,Class 的 Model 後面寫了很像 SQL ,
但又不太像 SQL 的地方,
那邊就是所謂『 ORM 』的概念,
這個部分我們明天會更詳細的介紹給大家喔!

如果有任何問題,或是指證文中的錯誤,歡迎寄信給我或留言在下面喔~


上一篇
[Day18] SQL 關聯語句 - join
下一篇
[Day20] 資料庫設計概念 - ORM
系列文
菜鳥後端工程師的第一門課30

尚未有邦友留言

立即登入留言