成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Web框架的常用架構(gòu)模式(JavaScript語(yǔ)言)

loostudy / 426人閱讀

摘要:只能在不同的時(shí)候選用不同的假設(shè)和不同的理論來(lái)解釋問(wèn)題,許來(lái)西的文章講到科學(xué)一定程度上通過(guò)放棄一貫性換取了實(shí)用性,放棄自洽性換取了它洽性。然而遺憾的是本身只提供了模塊和洋蔥模型的最小封裝。

在寫干貨之前,我想先探(qiang)討(diao)兩個(gè)問(wèn)題,模式的局限性?模式有什么用?

最近看到一篇文章對(duì)我啟發(fā)很大,許來(lái)西在知乎的回答《哲學(xué)和科學(xué)有什么關(guān)聯(lián)?》,全篇較長(zhǎng),這里摘錄我要引出的一點(diǎn):

科學(xué)作為一種經(jīng)驗(yàn)主義的認(rèn)識(shí)論,有著經(jīng)驗(yàn)主義的巨大缺陷:它永遠(yuǎn)不能產(chǎn)生絕對(duì)正確的真理。這是歸納法的本質(zhì)決定的。而且值得注意的是,歸納不具有唯一性。

舉一個(gè)簡(jiǎn)單的例子,我們假設(shè)一個(gè)世界,如下圖:

科學(xué)家很快有了兩種歸納方式:

世界上所有的青蛙都戴眼鏡

世界上所有戴眼鏡的都是青蛙

在沒(méi)有更多的信息的時(shí)候,我們應(yīng)該如何選擇正確的理論呢?答案是無(wú)法選擇。

舉個(gè)模式的例子,Scott Wlaschin 在《Functional Programming Design Patterns》(函數(shù)型編程模式)中對(duì)比了常用面向?qū)ο竽J?、原則,在函數(shù)型編程語(yǔ)言里面等價(jià)實(shí)現(xiàn):

OOP 和 FP,到底哪種編程范式更加先進(jìn)呢?答案同樣是無(wú)法選擇。只能在不同的時(shí)候選用不同的假設(shè)和不同的理論來(lái)解釋問(wèn)題,許來(lái)西的文章講到科學(xué)一定程度上通過(guò)放棄一貫性換取了實(shí)用性,放棄自洽性換取了它洽性??茖W(xué)追求實(shí)用和工具(實(shí)用主義和工具主義)。當(dāng)我看完許來(lái)西的文章,欣喜若狂,一直對(duì)編程技術(shù)理論的善變和不自洽感到恐懼和厭惡,其實(shí)只是經(jīng)驗(yàn)主義科學(xué)發(fā)展的必然過(guò)程,善變代表更好的理論(更方便)在替換基礎(chǔ)理論,代表蓬勃發(fā)展。

所以我想引入第一個(gè)觀點(diǎn):

模式是一套立足于特定背景,基于共性總結(jié)出的方案,它絕不是真理。

了解這些有助于幫助從對(duì)模式的盲目崇拜到探究它的實(shí)用性和工具性,也就是我要引出的第二個(gè)問(wèn)題:模式有什么用?

不好好寫代碼看哲學(xué)文章不是偶然,在文章落筆之前,我有思考過(guò)在 JavaScript 這門動(dòng)態(tài),多范式,單線程,基于事件I/O的語(yǔ)言環(huán)境下,甚至在當(dāng)前時(shí)代,模式是否還有意義?顯然我不是唯一這樣想的,還有篇深度好文《20年前GoF提出的設(shè)計(jì)模式,對(duì)這個(gè)時(shí)代是否還有指導(dǎo)意義?》。這篇文章引經(jīng)據(jù)典,摘錄了GoF(又稱Gang of Four,即Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides)在設(shè)計(jì)模式一書(shū)中觀點(diǎn):

這本書(shū)的實(shí)際價(jià)值也許還值得商榷。畢竟它并沒(méi)有提出任何前所未有的算法或者編程技術(shù)。它也沒(méi)能給出任何嚴(yán)格的系統(tǒng)設(shè)計(jì)方法或者新的設(shè)計(jì)開(kāi)發(fā)理論——它只是對(duì)現(xiàn)有設(shè)計(jì)成果的一種審視。大家當(dāng)然可以將其視為一套不錯(cuò)的教程,但它顯然無(wú)法為經(jīng)驗(yàn)豐富的面向?qū)ο笤O(shè)計(jì)人員帶來(lái)多少幫助。

換言之,模式顯然毫無(wú)實(shí)際用處。

不僅如此,文章還列舉了一度模式濫用導(dǎo)致許多弊端,可謂警鐘長(zhǎng)鳴。

但是……模式這一稱謂仍然不斷出現(xiàn),直到今天我們亦在大量使用。為什么?GoF實(shí)際早設(shè)計(jì)模式的書(shū)中做出了預(yù)言:

“設(shè)計(jì)模式為設(shè)計(jì)師們提供一種共通的詞匯儲(chǔ)備,幫助其溝通、編寫文檔并探索設(shè)計(jì)方案。設(shè)計(jì)模式允許我們立足于高級(jí)抽象層面進(jìn)行探討,而非設(shè)計(jì)標(biāo)注或者編程語(yǔ)言,這就大大降低了系統(tǒng)復(fù)雜性。設(shè)計(jì)模式提升了我們?cè)O(shè)計(jì)及與同事進(jìn)行設(shè)計(jì)探討時(shí)的切入點(diǎn)層級(jí)?!保ǖ?89頁(yè))

簡(jiǎn)言之,模式方便了我們的溝通,提升了思考問(wèn)題的抽象層級(jí)。

這個(gè)意義非常巨大,想象一下沒(méi)有 MVC 架構(gòu)模式,可能所有的 Web 框架必然的會(huì)實(shí)現(xiàn)一套幾乎解決同樣問(wèn)題的方案,但是命名和文檔卻各不一樣,當(dāng)你去看一個(gè)新的框架文檔的api 接口,從頭到尾看完以后才恍然大悟,這不就是之前用的框架里面的 XXX 類似嗎,這樣的編程世界簡(jiǎn)直地獄。慶幸的是,得益于計(jì)算機(jī)科學(xué)家(碼農(nóng))對(duì)問(wèn)題和方案持續(xù)的抽象成模式,使得當(dāng)前高度復(fù)雜的計(jì)算機(jī)科學(xué)也能得到合理分層和適配,大大簡(jiǎn)化了學(xué)習(xí)和溝通的成本。

為了感謝模式,是時(shí)候?qū)W習(xí)一波了,本文要介紹的主要有三種架構(gòu)模式:Middleware,MVC,DI。

Middleware 中間件模式

相信做過(guò) Node.js 服務(wù)端開(kāi)發(fā)的同學(xué)對(duì)這個(gè)模式一定不陌生,考慮如下 Web 應(yīng)用的場(chǎng)景:

在一個(gè)簡(jiǎn)單的 HTTP 請(qǐng)求響應(yīng)周期里,有如下條件處理,

記錄開(kāi)始時(shí)間

需要驗(yàn)證用戶的身份 authentication。

解析cookie 并加載body

根據(jù)路由返回不同的業(yè)務(wù)處理結(jié)果

沒(méi)有命中路由則返回404頁(yè)面

記錄日志

記錄總共花費(fèi)時(shí)間

處理異常并顯示頁(yè)面(開(kāi)發(fā)環(huán)境)

有些處理會(huì)根據(jù)是否成功決定是否繼續(xù)后面的粗粒,有些處理會(huì)生成額外的數(shù)據(jù),還有的要求攔截某些處理的開(kāi)始和結(jié)束,最后異常處理和記錄日志要求一定被執(zhí)行。

一般的解決方法是用嵌套條件判斷結(jié)合 try catch finally return 等控制語(yǔ)句,但是這樣的方案會(huì)導(dǎo)致代碼碎片化和復(fù)制粘貼的編碼風(fēng)格,因?yàn)榭刂屏骱瓦壿嬹詈系搅艘黄?。理想的方案?yīng)當(dāng)如下:

中心化控制流

解耦處理模塊(重用性)

聲明式、可配置的服務(wù)(配置和代碼無(wú)關(guān))

這些場(chǎng)景由來(lái)已久,很久以前J2EE總結(jié)了 Intercepting Filter 模式,有興趣大家可以看看這篇文(lun)章(wen),里面由淺入深提到三種方案,其中最初級(jí)的方案代碼如下:

public class DebuggingFilter implements Processor {
  private Processor target;
  public DebuggingFilter(Processor myTarget) {
    target = myTarget;
  }
  public void execute(ServletRequest req, 
  ServletResponse res) throws IOException, 
    ServletException    {
    // preprocess
    target.execute(req, res);
    // post-process
  }
}

這個(gè)和 express 和 Koa 的中間件模式極其相似,但是因?yàn)殪o態(tài)語(yǔ)言本身一些特征,導(dǎo)致最后形成的企業(yè)級(jí)代碼極其繁瑣,并且有許多局限性。最主要的問(wèn)題是處理模塊之間難以重用和共享數(shù)據(jù),因?yàn)?ServletRequest ServletResponse 無(wú)法動(dòng)態(tài)添加屬性。以至于 JavaEE 把這個(gè)模式的適用性加了許多限制,包括和核心處理邏輯分開(kāi)。

在動(dòng)態(tài)語(yǔ)言的世界里面,我們可以很方便的往 reqres 里面添加數(shù)據(jù)(基于約定),因?yàn)闆](méi)有了很多 OOP 世界里面的”束縛“,Node.js 的實(shí)現(xiàn)通常更加優(yōu)雅和通用。

Express 中間件模式

express 實(shí)現(xiàn)如今廣泛接受的 Middleware 中間件模式。中間件的意思是在 請(qǐng)求響應(yīng) 中間執(zhí)行的函數(shù)(為了區(qū)分另一個(gè)中間件),簽名如下:

var express = require("express");
var app = express();

這個(gè)模式包含了一套聲明式的路由規(guī)則,和 middleware 函數(shù)上的 next 簽名,它們共同構(gòu)成了整個(gè)中間件模式的控制流,如圖:

這個(gè)模式的核心構(gòu)成不是權(quán)限,解析等中間件邏輯,而是路由判斷next中斷響應(yīng)(驗(yàn)證失敗、解析失?。?/b>,其作為中間件執(zhí)行控制,解耦了具體的處理邏輯,使得更容易寫出通用的細(xì)粒度的中間件。express 內(nèi)置的強(qiáng)大的聲明式路由,并且路由和 middleware 分離可以說(shuō)是它最成功的設(shè)計(jì)之一。

然而在一些稍微復(fù)雜點(diǎn)的業(yè)務(wù)中,比如一個(gè)網(wǎng)站有管理端和用戶端,兩個(gè)端相當(dāng)于獨(dú)立的app。express 4.0 提供了一個(gè)非常強(qiáng)大的功能 Router。Router 拓展了鏈?zhǔn)經(jīng)Q策變成樹(shù)形決策,可以讓 express 更好的支持大型項(xiàng)目。

/*  
   文件  bird.js
*/
var express = require("express")
var router = express.Router()
  
router.get("/", function (req, res) {
  res.send("Birds home page")
}) 

module.exports = router

/*  
   文件  app.js
*/

var birds = require("./birds")

// ...

app.use("/birds", birds)

Koa 異步中間件模型

Koa 的異步中間件模式-洋蔥模型,相比 Express,其中間件函數(shù)返回 Promise,支持 async/await,并且可以輕松實(shí)現(xiàn)前置和后置的處理。毫無(wú)疑問(wèn)這個(gè)模式更加先進(jìn),一些在 express 里面不好實(shí)現(xiàn)的攔截處理邏輯,比如異常處理和統(tǒng)計(jì)時(shí)間,在 Koa 里用一個(gè)中間件就能搞定。然而遺憾的是 Koa 本身只提供了 Http 模塊和洋蔥模型的最小封裝。

未來(lái)我看好 Koa,其實(shí) express 也意識(shí)到這點(diǎn),他們計(jì)劃在 5.0 版本里添加 Promise 的支持,然而作為一個(gè)老牌和完整生態(tài)的框架,要克服的困難遠(yuǎn)不是技術(shù)層面上看似的簡(jiǎn)單,直到目前仍然沒(méi)有看到 5.x 宣布支持 Promise, 讓我們拭目以待。

MVC 模式

MVC 模式也需要介紹嗎,我們天天都在聊 MVC,不管前、后端框架,說(shuō)一句 MVC,對(duì)一下眼神,基本確定對(duì)方懂你了。

事實(shí)是,前端框架已經(jīng)不適合用 MVC 討論,這個(gè)模式從1979年提出以來(lái),作為萬(wàn)精油模式,在各個(gè)框架和場(chǎng)景中被套用,背負(fù)了太多的歷史包袱,大家可以看 winter 的文章 談?wù)刄I架構(gòu)設(shè)計(jì)的演化。撥亂反正我覺(jué)得有希望,討論前端框架大家以后統(tǒng)稱 MV 模式就好了,就是模型和視圖分離。

我們今天要講的 MVC 模式是指在服務(wù)器上(后端) MVC 模式,它的定義經(jīng)受了時(shí)間和實(shí)踐的檢驗(yàn),在許多企業(yè)級(jí) Web 框架的實(shí)現(xiàn)中高度一致。先列舉場(chǎng)景:

如果你的網(wǎng)站只有幾個(gè)簡(jiǎn)單的頁(yè)面,所有邏輯都寫在 Controller 里面,是沒(méi)有問(wèn)題的。隨后網(wǎng)站迅速的增長(zhǎng),你發(fā)現(xiàn),

許多頁(yè)面里面的視圖是一致的,但是背后的數(shù)據(jù)模型不一致。比如:網(wǎng)站上幾乎沒(méi)有一個(gè)視圖或者組件是獨(dú)一無(wú)二的,表格,下拉框等。

許多頁(yè)面里面的數(shù)據(jù)模型是一樣的,但是展現(xiàn)的視圖不一致。比如:同時(shí)支持PC和移動(dòng)端,國(guó)際化本地化。

我們做一個(gè)數(shù)學(xué)模型模擬極端情況,大家很容易能看到問(wèn)題

假設(shè)左邊是我們的系統(tǒng)最終的樣子,它剛好可以表示成 M(模型)和 V(視圖)的內(nèi)積,我們更傾向于右邊的表達(dá),因?yàn)樗?jiǎn)潔而且沒(méi)有重復(fù)。這里的內(nèi)積操作大家就可以理解成控制器,實(shí)際上不會(huì)如此巧合,但是分離模型和視圖幫助我們提高代碼復(fù)用,降低設(shè)計(jì)復(fù)雜度的好處是很顯然的,一個(gè)更通用的表達(dá)

模型視圖和控制器之間都是單向鏈接,所以整個(gè)系統(tǒng)的行為非??煽厍胰菀诇y(cè)試,多帶帶把路由分開(kāi)是想強(qiáng)調(diào) Router 和 Controller 是兩個(gè)概念,Router 只是一個(gè)觸發(fā)器(或者提供了一種映射關(guān)系),在寫測(cè)試的時(shí)候,我們也可以跳開(kāi) Router 多帶帶調(diào)用 Controller。

看到上面的兩種模式,是不是已經(jīng)開(kāi)始想,那有沒(méi)有一個(gè)框架同時(shí)是 Koa + Router + MVC 呢,推薦大家一個(gè)非常好用的企業(yè)級(jí) Web 框架 ThinkJS 3.0,最新版的 ThinkJS 集成了大量最佳實(shí)踐和完善的文檔,不管是學(xué)習(xí)或者企業(yè)級(jí)開(kāi)發(fā)都非常推薦。而且 ThinkJS 同樣實(shí)現(xiàn)了接下來(lái)要講的模式。

DI 依賴注入模式

還是先說(shuō)場(chǎng)景,假如服務(wù)端需要實(shí)現(xiàn)session,前期考慮到成本和用戶量,單臺(tái)服務(wù)器存到文件就夠用了。后期如果用戶量大的時(shí)候,需要橫向擴(kuò)展(Scale-out),就把 session 實(shí)現(xiàn)基于中心化的 Redis 服務(wù)。

我們系統(tǒng)設(shè)計(jì)目標(biāo)是:

不需要修改業(yè)務(wù)邏輯代碼實(shí)現(xiàn)替換

不需要關(guān)注服務(wù)的創(chuàng)建和生命周期

解決這類系統(tǒng)擴(kuò)展性問(wèn)題有一個(gè)非常著名的設(shè)計(jì)原則 控制反轉(zhuǎn)(IoC Inversion of control),而 依賴注入(DI dependency injection) 就是其中的一個(gè)實(shí)現(xiàn)模式。

DI 的基本思路是這樣,首先我們的代碼不能依賴具體的服務(wù),需要總結(jié)歸納出一套抽象接口,業(yè)務(wù)實(shí)現(xiàn)依賴接口,而服務(wù)實(shí)現(xiàn)接口,最后通過(guò)框架專門負(fù)責(zé)創(chuàng)建和提供接口的實(shí)例。

這里的 IoC 容器或者說(shuō) Ioc 框架,會(huì)在啟動(dòng)的時(shí)候讀取配置文件,并在運(yùn)行的時(shí)候根據(jù)需要?jiǎng)?chuàng)建實(shí)例提供給使用者,在靜態(tài)語(yǔ)言如 java,c# 需要用到反射等高級(jí)語(yǔ)法,而 JavaScript 本身是動(dòng)態(tài)的,接口基于約定,并且使用的方式也更加靈活。比如 ThinkJS 3.0 里面的 extendadapter 就可以理解成接口和實(shí)現(xiàn),如圖:

那之所以稱為 extend,是因?yàn)榭蚣軙?huì)直接把接口注入到 controller 或者 think 對(duì)象中。這樣的好處是使用起來(lái)更方便,缺點(diǎn)是不同 extend 需要約定好不能重名。

最后

本文介紹的三個(gè)架構(gòu)模式,你會(huì)發(fā)現(xiàn)幾乎在所有的Web框架實(shí)現(xiàn)都大同小異,這就是模式的好處。模式的意義類似于 IoC,我關(guān)注抽象和接口,抹平了具體語(yǔ)言特性下的細(xì)節(jié)問(wèn)題,幫助我們更好的學(xué)習(xí),溝通和思考。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95023.html

相關(guān)文章

  • 全棧開(kāi)發(fā)自學(xué)路線

    摘要:前言這里筑夢(mèng)師是一名正在努力學(xué)習(xí)的開(kāi)發(fā)工程師目前致力于全棧方向的學(xué)習(xí)希望可以和大家一起交流技術(shù)共同進(jìn)步用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程個(gè)人學(xué)習(xí)方法分享本文目錄更新說(shuō)明目錄學(xué)習(xí)方法學(xué)習(xí)態(tài)度全棧開(kāi)發(fā)學(xué)習(xí)路線很長(zhǎng)知識(shí)拓展很長(zhǎng)在這里收取很多人的建議以后決 前言 這里筑夢(mèng)師,是一名正在努力學(xué)習(xí)的iOS開(kāi)發(fā)工程師,目前致力于全棧方向的學(xué)習(xí),希望可以和大家一起交流技術(shù),共同進(jìn)步,用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程...

    galaxy_robot 評(píng)論0 收藏0
  • 全棧開(kāi)發(fā)自學(xué)路線

    摘要:前言這里筑夢(mèng)師是一名正在努力學(xué)習(xí)的開(kāi)發(fā)工程師目前致力于全棧方向的學(xué)習(xí)希望可以和大家一起交流技術(shù)共同進(jìn)步用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程個(gè)人學(xué)習(xí)方法分享本文目錄更新說(shuō)明目錄學(xué)習(xí)方法學(xué)習(xí)態(tài)度全棧開(kāi)發(fā)學(xué)習(xí)路線很長(zhǎng)知識(shí)拓展很長(zhǎng)在這里收取很多人的建議以后決 前言 這里筑夢(mèng)師,是一名正在努力學(xué)習(xí)的iOS開(kāi)發(fā)工程師,目前致力于全棧方向的學(xué)習(xí),希望可以和大家一起交流技術(shù),共同進(jìn)步,用簡(jiǎn)書(shū)記錄下自己的學(xué)習(xí)歷程...

    Scorpion 評(píng)論0 收藏0
  • JavaScript 就要統(tǒng)治世界了?

    摘要:歡迎使用中文文檔架構(gòu)概覽是網(wǎng)易項(xiàng)目團(tuán)隊(duì)開(kāi)發(fā)的一個(gè)基于進(jìn)行開(kāi)發(fā)的應(yīng)用層框架,提供了一個(gè)輕量級(jí)的容器來(lái)編寫簡(jiǎn)單可維護(hù)的。 JavaScript 可以……嘛,不就是操作一下 DOM,可以讓元素飛來(lái)飛去嗎JavaScript 是……不就是用 jQuery 讓網(wǎng)頁(yè)動(dòng)起來(lái),頂多就是再用用 Ajax 和后端進(jìn)行一下數(shù)據(jù)交換嗎JavaScript 是一門……最討厭和鄙視這種弱類型不需要編譯的腳本語(yǔ)言...

    AbnerMing 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<