聊聊MVC和模組化以及MVVM和元件化

白小寒發表於2019-03-04

原文來自 小寒的部落格

物件導向,模組化和MVC

物件導向是指把寫程式對映到現實生活,從而一來邏輯性更強,更容易寫好程式碼,二來程式碼很貼切,通俗易懂,更被人理解,三來更加容易擴充和管理程式碼。
我們的程式碼設計應該有很多人,事物和場景,人是管理員,事物是資料庫,場景就是業務。

物件導向

寫程式碼就像在模擬現實的生活的處理公務,比如我們可以抽象出一些人幫我們來幹活。
文章管理員,負責文章的CRUD,文章分類的CRUD
使用者管理員,oauth passport和CRUD
郵件管理員,send email,郵件模版的CRUD
簡訊管理員,send SMS,簡訊模板的CRUD
訊息管理員,send notification,站內和站外訊息模版的CRUD
還有客戶端管理員,交易管理員等等等等。。。
分散式開發中,還會借用一些其他伺服器的管理員。
當然這裡抽象出來多個管理員,還可以抽象出文章儲存室,使用者資訊儲存室這樣的被管理的物件。

模組化

把程式碼按照功能和資料分成多個模組,文章模組,使用者模組,郵件模組等等,一個模組可能對應多個管理員,比如文章模組裡他可能有文章分類管理員,文章管理員,文章檢視歷史管理員。
模組可以理解為這個世界上有不同的行業,也可以理解為一個家裡也有不同的分工,所以分模組可大可小,可以在大的模組裡去區分子模組。總之模組是為了解決業務的耦合。就像分行業也是為了解決社會的耦合,但模組之間並不會區分的很徹底,就像各行各業總會有所關聯,所以這也需要程式設計者們把握好度了。

模組之間的管理員之間是除了有分工之外,還有很大的合作。比如2C的應用裡使用者管理員總是需要忙個不停,因為他總要跑來跑去的幫助其他模組去識別使用者

我們實現一個很複雜的功能,需求是這樣的
某使用者的部落格釋出之後需要其他的人登陸後才可以檢視,檢視的時候會給部落格作者發個簡訊,告訴博主有人來看你的簡訊了,再給來看部落格的人發個郵件說歡迎光臨。
1. user = await UserManager.getByToken(req.header.token)
2. if (user) blog = await BlogManager.getById(req.params.blogId)
3. res.send(blog) 
    && SMSManager.send(blog.author.phone, 'blog-be-read')
    && EmailManager.send(user.email, 'welcome')複製程式碼

MVC

這裡呢UserManager BlogManager SMSManager EmailManager都是controller,理解為控制資料。
res.send(blog) 中的blog是view,可以理解為要呈現給前端的東西。
這些管理圓管理的模版和資料庫則屬於model,可以理解為原始的資料。

mvc是應對複雜業務場景的後臺最常見的設計模式,會把程式抽象成三層,就像在物件導向裡說的那樣,一個程式應該有人,事物,業務,其實也可以理解為人就是controller,事物是model,業務是view。對於web後端來說view經常會是web前端。

前端的MVC

類比於後端的MVC
在前端
M指的是後臺給的資料,即原始資料
V仍然是要呈現的資料,但是是呈現給使用者的介面
C值得是處理後臺的資料和view層的互動邏輯
具體實現呢
// model
model = res.data

// controller
view.date = Formater.formatTime(model.date)
view.author = Formater.formatUserName(model.author)
view.blog = BlogController.beautify(model.blog)

// view
document.write(view.author)
document.write(view.date)
document.write(view.blog)複製程式碼
document.write相對於res.send是一樣的
前端也會有一些工作人員比如 Formater, BlogController也是控制資料的
是不是和後端很像呀
不同的是前端的view很複雜model很簡單,後端的model很複雜view很簡單。
聊聊MVC和模組化以及MVVM和元件化

前端對MVC的不足

前端的view可能只是在展示資料,這樣的網站很適合用MVC,比如管理系統,一個頁面一個table的那種。
但也很可能非常複雜,比如在2C的程式中頁面可能要肩負各種複雜的操作,操作太瑣碎,controller就會變得很臃腫。比如說這個網站裡的音樂播放器,要有

上一首,下一首,隨機播放,單曲迴圈,音量,顯示列表,顯示歌詞,關閉歌詞,顯示列表,選擇歌曲,關閉列表,暫停,繼續,快進,快退,更新播放時間等等等等的功能。。。這個時候功能這些功能要全部寫在controller裡同時還要發起請求更新資料,監聽時間變化,controller就很複雜。
我們通常都是請求一次後臺,然後塞一個列表進去,然後使用者切換音樂只是在本地記憶體裡讀取資料。

這個時候就會有問題
1. 前端的複雜的操作不像後塊化那樣可以解耦,前端頁面之間,元件之間的耦合應該如何處理
2. 前端的複雜的操作太多了,controller要處理事件還要處理請求,如何減輕維護controller的成本
3. 單頁面應用中需要在前端維護一份資料,這份資料只是臨時的,不可以放在後端的model裡應該放在哪

同時我們也會發現,複雜的業務場景裡view和controller的事件處理部分邏輯關係相當密切,所以開發者經常會把controller和view封裝在一起,這個時候就出現了元件。
而開發者會在前端暫存一封資料,因為瀏覽器不用經常重新整理了,不需要經常發起請求,因此出現了vm,意指view model。和model的區別就是他是針對view的model。
就這樣出現了mvvm和元件化

元件化和MVVM

MVVM

歸根結底的說MVC不適合前端的一些業務場景就是因為後端V會相對簡單,重點在於解決controller和model的關係。前端的V很複雜,重點在於解決view和controller的問題。

在MVVM中
M不變,可以認為他是資料來源,M很簡單,但資料往往不是view需要的。
V是UI和使用者輸入。面對複雜的使用者操作而且要迅速給予反饋,操作和展示往往是同時存在的,比如一個表單就肯定會有表達資料和接受輸入兩種屬性。這就是元件,元件同時具有兩種能力,接受輸入獲取反饋也是MVVM裡的第二個V。
VM是在單頁應用裡出現的一種概念,在單頁面的應用裡資料在使用者不重新整理的狀態下可以一直暫存在瀏覽器的記憶體裡,因而把資料請求到本地之後就快取在客戶端的記憶體裡,可以大幅度的複用資料,同時也需要有一層類似於資料庫的VM是專門為V提供的model,所以他必須給V更加準確和舒適的資料,以及獲取資料和修改資料的方式。同時VM也要減少V裡複雜的controller裡的api冗餘,避免過於繁重的controller,所以和VM也需要負責發起請求。

最後結論就是。
M是response data
V是view + user action controller
VM是store + request controller
聊聊MVC和模組化以及MVVM和元件化
這樣寫的好處有
1. view中加入controller可以增強元件化,view和controller更加密切,可以專注的的表達UI和互動邏輯,把前端的任務大幅度專注在使用者體驗和UI構建上。
2. 分離model和view之間的直接聯絡,把和後端交流的任務分配給了view model,確保view拿到的資料更加優雅和易用。
3. 前端暫留一份資料層,供自己的UI使用。同時也把請求資料,處理後臺資料的任務給了vm。大幅度減少了controller裡的程式碼。還能起到複用請求和處理資料程式碼的好處。

元件化

元件化也是物件導向的一種表現。但是元件化和模組化開發在感覺上會又很大的區別。
元件是一種有著強大功能的 "dom" 元素。
元件的任務是使用者體驗和UI構建。
比如這個部落格網站就是由 1. 留言表單 2. 逐個出現的動畫元件,3. 音樂播放器,4. 音樂背景牆和歌片語件,5. 部落格導航選單元件 6. 歌單元件 7 歌曲元件 8 導航元件 9 底部元件 10 部落格內容 11 部落格列表 構成。
我羅列了以下,意思就是說這麼大的一個網站其實可以只是這麼幾個元件而已,這就是元件化的好處。專注構建UI和提升使用者體驗。

前端元件分類

從bootstrap開始元件分類就已經開始了,通常我們會認為有
antd分為通用,佈局,導航,資料錄入,資料展示,反饋和其他
這個分類很難以辯駁,個人覺得比較合理,但是這種分類的依據很難說的出來。因為上學的時候,書本里的分類前都會說按照XXX分類可以分為。但是antd這個分類方法就不容易感知到了。
比如通用和資料錄入顯然並不是一種分類方法。通用是表達元件的使用範圍廣度,資料錄入是按照功能劃分的
再比如資料展示和反饋很可能差不多,只是反饋不是直接的資料展示。
但細想以下,這種分類確實也表現出了各個類別裡元件的特點。總之分類只是便於理解。因為分不開呀。

我通常會把元件的作用分為以下三種
1. 用於資料展示的
2. 用於接受使用者操作的
3. 輔助和增強功能

嚴謹的說這個是分類元件的功能,而不是給元件分類。而幾乎大多陣列件都很容易就具有1 2 兩種屬性。並不容易確定元件屬於某種功能,但能看出他們更傾向於那種。

比如
Collapse就是輔助和功能性的,我們市面上見到的都是CollapsePanel這個元件,而Panel是展示資料的元件。
Table就是資料展示的,被我們擴充封裝之後呢,我們用到的Table很可能是TableWithPagination,這就讓Table就可以接受使用者輸入了。但Table是更傾向於展示資料的元件
Button是更傾向於使用者操作的元件,因為他很能展示文字。

所以可以發現我們用到的元件大多都是有不同的屬性的,就像問道里的人物角色一樣,三敏一體一力 什麼什麼的,就是敏捷型的角色。

網站本身是傾向於資料展示的一種應用。因此有些也不好歸類為更傾向於某種功能,篇幅有限,總之這個話題想要得到一個比較妥善的答案可以討論幾千字吧。

React不是框架

React是一個構造可組合式使用者介面的庫,它鼓勵建立可重用的UI元件去顯示會隨著時間而改變的資料。
很多人寫react的出發點是錯的,和angular,vue出發點並不相同。facebook發明react的原因是在富互動時代的web開發中,如何更好的組織UI是一個很棘手的問題,而通過元件的方式可以很好的解決了這個問題,所以發明了react。

所以說白了react只是一個解決UI問題的工具庫而已,使用這個庫我們可以很方便的構建一些複雜的互動和樣式,並把網站抽象成一個個元件,然後簡化web UI的開發,而配合這個庫使用解決其他問題的比如react-redux,
react-router等等則是解決web開發的除了UI以外的資料管理和路由等問題的。

如果不能抽象UI,那麼用react可能對你來說並不合適甚至很可能是一種累贅,用vue或者ng可以大幅度減少程式碼量

參考連結:


相關文章