iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 11
5
Modern Web

Node JS-Back end見聞錄系列 第 11

Node.js-Backend見聞錄(10):關於後端觀念(六)-關於MVC

Node.js-Backend見聞錄(10):關於後端觀念(六)-關於MVC

前言

關於後端觀念(五)-關於框架-Express後,接著我們要談關於Express的MVC架構,但在這之前,讓我們先看看MVC的概念。之後,筆者會在講述Node.js的MVC架構,及Express的MVC架構。讓讀者們能理解它們的不同之處。

MVC

MVC(Model–view–controller)為軟體工程中的一種軟體架構模式。它由三個部分所形成:

Model

主要用來處理資料的邏輯及資料庫的部分。只要是與資料相關的事情,都會交由它處理。

View

將Model的資料透過View來呈現給使用者。

Controller

藉由使用者的行為來控管及觸發特定的事件,並指示該事件所對應的Model來進行處理。

使用MVC架構的好處就是能協助我們進行程式的維護,這是因為我們賦予程式一個職責分離的設計,使每個程式能夠專心做自己須負責的事情。這不僅利於維護,同時也能讓我們針對各個不同的功能去做測試的動作。試想著,如果我們沒有將程式進行職責分離的動作,這可能會讓單一檔案的程式碼非常的長。若日後發生問題,或是需求改變需要更改特定程式碼...等。眾多例外情況造成維護上或後續開發上的不便。

舉個例子,若今天程式要進行交接的動作,前人所留下來的程式碼又臭又長,且沒有做MVC或職責分離的動作。當你今天要做code review應該會是一件非常痛苦的事情。

註記:MVC之間關係的圖在網路上有非常多的派別,所以筆者這邊就不畫出它們之間的交集圖。且不同的語言或框架其MVC也會有些許不同。當然,釐清他們之前的處理順序固然重要,但最重要還是希望讀者能先知道它們各自負責的項目為何。

Node.js MVC

在Node.js中的MVC運作會是這樣:

  1. Client端發送一個request至server端。
  2. 待Server端收到後,會由controller部分來接收request的訊息,並進行剖析的動作。
  3. Controller找出與request所相對應的model,並將request交由該model處理。
  4. model處理完後,將資料再交回給controller,並讓controller交付給view做處理。
  5. 透過view產生出能讓client所看到的html檔案,並將其結果轉交給server端。
  6. 藉由server端來發送response給client端。

註記:
如果單純只做出API,第5步驟就會變成:
Controllermodel處理完的結果交由server端。

Express MVC

在Express中,若我們使用Express的快速建置開發環境的方式產生Express專案的話,其MVC運作會是這樣:

  1. Client端發送request至server端。
  2. Server端將收到的request由特定的router來做處理。
  3. 若收到的request需要跟DB來做撈取資料的動作,則從DB中找尋該資料,並將資料回傳至router中。若無則直接對資料進行後處理的動作。
  4. router處理完資料的邏輯後,將其結果傳給view,並由view來產生html文件。
  5. 藉由router來將view所產生的html文件送至server端中。
  6. Server端回覆response至clietn端。

註記:
如果單純只做出API,會跳過第4步驟且第5步驟就會變成:
藉由router將處理完的結果交由server端。

讀者可以發現,藉由Express的快速建置開發環境的專案中,Router本身就會涵蓋了controllermodel的部分。

其資料結構會是:

.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.ejs
    └── index.ejs

也就是說我們將controllermodel的部分都集中寫在routers資料夾底下。假設以routers資料夾中的index.js來說,其程式碼會是:

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
    // do something
    // 連接資料庫
    // 從資料庫將資料撈完後進行res.render的動作。
});

module.exports = router;

註記:res.render指Express中,讓處理完的資料傳送到view的指令。

自定義的Express MVC

若使用Express的快速建置開發環境的專案,是還沒有做到職責分離的動作,我們可以試著將controllermodel加入其中,其運作會是:

  1. Client端發送request至server端。
  2. Server端接收到request後,交由特定的router的function所接收,並呼叫相對應的controller
  3. 透過相對應的controller function來呼叫特定的model做處理。
  4. 若該request需要與DB來做撈取資料的動作,則從DB中找尋該資料,並將資料回傳至model中。若無則直接對資料進行後處理的動作。
  5. model處理完資料的邏輯後,將其結果回傳至controller中。
  6. Controllermodel的資料傳給view,並由view來產生html文件。
  7. 藉由controller來將view所產生的html的文件送至server端中。
  8. Server端回覆response至client端。

註記:
如果單純只做出API,會跳過第6步驟且第7步驟就會變成:
藉由controllermodel處理完的結果交由server端。

資料結構就會變成:

.
├── app.js
├── bin
│   └── www
├── controllers
│   ├── index_controller.js
├── models
│   ├── index_model.js
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.ejs
    └── index.ejs

也就是我們加入了controllersmodels的資料夾,並讓底下的js擋來分別負責處理controllermodel的部分。

其程式碼的部分就會變成:

  • routers資料夾的index.js
const IndexController = require('../controllers/index_controller');

indexController = new IndexController();

router.get('/', indexController.sayHiController);
  • controllers資料夾的index_controller.js
const IndexModel = require('../models/index_model');

indexModel = new IndexModel();

module.exports = class IndexController {
    sayHiController(req, res ,next) {
        // do something
        // 呼叫特定的model
        // 從資料庫將資料撈完後進行res.json的動作。
    }
}

  • models資料夾的index_model.js
module.exports = class IndexModel {
    sayHiModel(req, res ,next) {
        // do something
    }
}

小結

藉由上述的介紹,讀者應該對於MVC有更近一步的瞭解了。但筆者提醒「MVC不是一種技術,是一種理念。」MVC的重點在於分化程式的職責,且其運用是非常多元化的。並非今天筆者提出了這種MVC的做法就一定是正確的。今天開發一個專案,專案上要怎麼分化整個程式的職責,其實都是由當時的情況來做考量。且若有一同開發後端的工程師夥伴,就需要跟他們進行溝通,並商榷要用什麼方式來進行開發。

接續,下個分享我們將提及「如何設定資料庫」。

參考資料

Creating an MVC framework for our Node.js page - getting ready for scalability


上一篇
Node.js-Backend見聞錄(09):關於後端觀念(五)-關於框架-Express
下一篇
Node.js-Backend見聞錄(11):關於後端觀念(七)-如何設定資料庫
系列文
Node JS-Back end見聞錄31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

1
oliver
iT邦新手 5 級 ‧ 2019-05-02 14:50:04

好文推推

/images/emoticon/emoticon37.gif

0
singer0503
iT邦新手 5 級 ‧ 2020-05-29 10:06:57

樓主好,您文章內的程式碼如下:

  • controllers資料夾的index_controller.js
const IndexController = require('../controllers/index_controller');
// 以下省略...

這段應該有誤?

應修改為:

const IndexModel = require('../models/index_model'); // <-- 這裏

indexModel = new IndexModel();
module.exports = class IndexController {
    sayHiController(req, res ,next) {
        // do something
        // 呼叫特定的model
        // 從資料庫將資料撈完後進行res.json的動作。
    }
}

依我理解應該是 controller 需要 import model
這樣對嗎? 剛學 node 不太確定,還講解惑,謝謝~

感謝 singer0503 的抓蟲。

對,這部分的確是我的失誤。

「依我理解應該是 controller 需要 import model」

是的,controller 是要提取 model 裡的 function 資料沒錯。

我要留言

立即登入留言