成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

模式系統(tǒng)與最簡單的Node.js MVC Web Server設(shè)計

codercao / 1421人閱讀

摘要:模式記錄了已得到充分證明的既有設(shè)計經(jīng)驗。模式有助于創(chuàng)建具有指定特征的軟件。每個模式都說明了運行階段的行為。應用設(shè)計模式不會影響軟件系統(tǒng)的基本架構(gòu),但可能嚴重影響子系統(tǒng)的架構(gòu)。成例如何解決特定的設(shè)計問題。

學了這么久的設(shè)計模式,最近一直在看Node.js的設(shè)計模式,一直納悶為何會有模式這一類東西的存在,那么模式究竟是什么東西?后面在看了《面向模式的軟件架構(gòu)》之后才慢慢知道有了一些系統(tǒng)的概念。

模式是什么?

面對特定問題時,專家很少去尋找與既有解決方案截然不同的新方案,而通常會想起一個以前解決過的類似問題,并將其解決方案的精髓用于解決這個新問題。

從特定問題—解決方案中提煉出通用的因素便可得到模式:這些問題—解決方案通常是一系列熟悉的問題和解決方案,其中每對問題—解決方案都呈現(xiàn)出相同的模式。

Model-View-Controller模式

MVC模式大量用在現(xiàn)代軟件開發(fā)流程中,為何會有MVC模式的存在,來看這一個例子:開發(fā)帶人機界面的軟件。

用戶界面需求容易變化。例如,添加應用程序功能時,必須修改菜單以便能夠訪問新功能,還可能需要針對特定客戶調(diào)整用戶界面。系統(tǒng)可能需要移植到另一個平臺,而該平臺采用的“外觀”標準完全不同。即便是升級到新的窗口系統(tǒng)版本,也可能需要修改代碼??傊?,如果系統(tǒng)的使用壽命很長,可能經(jīng)常需要修改用戶界面。設(shè)計靈活的系統(tǒng)時,讓用戶界面與功能核心緊密地交織在一起將付出高昂的代價,且容易出錯。這樣做的后果是,可能需要開發(fā)和維護多個大不相同的軟件系統(tǒng)——每種用戶界面實現(xiàn)一個,且修改將涉及眾多不同的模塊??傊?,開發(fā)這種交互式軟件系統(tǒng)時,必須考慮如下兩個方面:

應該能夠輕松地修改用戶界面,在運行階段就能完成;

調(diào)整或移植用戶界面時,不應影響到應用程序功能核心的代碼。

為解決這種問題,應將交互式應用程序劃分成三部分:處理、輸出和輸入。

模型(model)組件封裝核心數(shù)據(jù)和功能,獨立于輸出表示方式和輸入行為。

視圖(view)組件向用戶顯示信息。視圖從模型那里獲取它顯示的信息,一個模型可以

有多個視圖。

每個視圖都有相關(guān)聯(lián)的控制器(controller)組件??刂破鹘邮茌斎?,通常是表示鼠標移動、鼠標按鈕激活或鍵盤輸入的事件。事件被轉(zhuǎn)換為服務請求,而服務請求要么被發(fā)送給模型,要么被發(fā)送給視圖。用戶只通過控制器與系統(tǒng)交互。

通過將模型與視圖和控制器組件分開,讓同一個模型可以有多個視圖。如果用戶通過一個視圖的控制器修改了模型,這種變更應在依賴相關(guān)數(shù)據(jù)的其他所有視圖中反映出來。為此,每當模型的數(shù)據(jù)發(fā)生變化時,它都會通知所有視圖,而視圖將從模型那里檢索新數(shù)據(jù),并更新顯示的信息。這種解決方案確保了修改應用程序的一個子系統(tǒng)時不會嚴重影響其他子系統(tǒng)。例如,可將非圖形用戶界面改成圖形用戶界面而無需修改模型子系統(tǒng),還可支持新的輸入設(shè)備而不影響信息的顯示和功能核心。所有軟件版本都可依賴同一個模型子系統(tǒng),該子系統(tǒng)獨立于“外觀”。

用Model-View-Controller模式實現(xiàn)一個鑒權(quán)服務

我們從下圖所示的結(jié)構(gòu)開始分析:

上圖顯示了Model-View-Controller模式的典型示例;它描述了一個簡單的鑒權(quán)服務的結(jié)構(gòu)。AuthController接受來自客戶端的輸入,從請求中提取登錄信息,并執(zhí)行一些初步驗證。之后AuthService檢查客戶端提供的憑證是否與存儲在數(shù)據(jù)庫中的信息匹配;最后使用db模塊執(zhí)行一些特定的查詢來完成的,作為與數(shù)據(jù)庫通信的一種手段。這三個組件連接在一起的方式將決定應用程序的可重用性,可測試性和可維護性。

在這里:模型(Model)指的就是db模塊,控制器(Controller)指的就是AuthControllerAuthService,而視圖則是前端的用戶界面,也就是HTML文檔。

將這些組件連接在一起的最自然的方法是通過AuthService請求db模塊,然后從AuthController請求AuthService。

讓我們通過實際實現(xiàn)剛剛描述的系統(tǒng)來演示這一點。那么我們來設(shè)計一個簡單的鑒權(quán)服務器,它將有以下兩個HTTP API

POST "/ login":接收包含用戶名和密碼對進行身份驗證的JSON對象。 成功時,它會返回一個JSON Web Token(JWT),隨后的請求中使用它來驗證用戶的身份。

GET"/ checkToken":查看用戶是否具有權(quán)限。

對于這個例子,我們將使用幾種技術(shù);這對我們來說并不陌生。我們使用express來實現(xiàn)Web API和levelup來存儲用戶的數(shù)據(jù)。

db模塊

我們先從底層開始構(gòu)建應用程序;首先實現(xiàn)levelUp數(shù)據(jù)庫實例的模塊。我們來創(chuàng)建一個名為lib/db.js的新文件,其中包含以下內(nèi)容:

const level = require("level");
const sublevel = require("level-sublevel");
module.exports = sublevel(
  level("example-db", {
    valueEncoding: "json"
  })
);

前面的模塊是存儲在./example-db目錄中的LevelDB數(shù)據(jù)庫的連接,然后使用sublevel來修飾實例,通過這一模塊實現(xiàn)了增刪查改數(shù)據(jù)庫。模塊導出的對象是數(shù)據(jù)庫對象本身。

authService模塊

現(xiàn)在我們有了db單例,我們可以使用它來實現(xiàn)lib/authService.js模塊,它負責查詢數(shù)據(jù)庫,根據(jù)用戶身份憑證查看用戶是否具有權(quán)限。 代碼如下(只顯示相關(guān)部分):

"use strict";

const jwt = require("jwt-simple");
const bcrypt = require("bcrypt");

const db = require("./db");
const users = db.sublevel("users");

const tokenSecret = "SHHH!";

exports.login = (username, password, callback) => {
  users.get(username, (err, user) => {
    if(err) return callback(err);
    
    bcrypt.compare(password, user.hash, (err, res) => {
      if(err) return callback(err);
      if(!res) return callback(new Error("Invalid password"));
      
      let token = jwt.encode({
        username: username,
        expire: Date.now() + (1000 * 60 * 60) //1 hour
      }, tokenSecret);
      
      callback(null, token);
    });
  });
};

exports.checkToken = (token, callback) => {
  let userData;
  try {
    //jwt.decode will throw if the token is invalid
    userData = jwt.decode(token, tokenSecret);
    if (userData.expire <= Date.now()) {
      throw new Error("Token expired");
    }
  } catch(err) {
    return process.nextTick(callback.bind(null, err));
  }
    
  users.get(userData.username, (err, user) => {
    if (err) return callback(err);
    callback(null, {username: userData.username});
  });
};

authService模塊實現(xiàn)login()服務,該服務負責查詢數(shù)據(jù)庫,檢查用戶名和密碼信息,checkToken()服務接受token作為參數(shù)并驗證其有效性。

authController模塊

繼續(xù)在應用程序的層次上,我們現(xiàn)在要看看lib/authController.js模塊。這個模塊負責處理HTTP請求,它本質(zhì)上是Express路由的集合;該模塊的代碼如下:

"use strict";

const authService = require("./authService");

exports.login = (req, res, next) => {
  authService.login(req.body.username, req.body.password,
    (err, result) => {
      if (err) {
        return res.status(401).send({
          ok: false,
          error: "Invalid username/password"
        });
      }
      res.status(200).send({ok: true, token: result});
    }
  );
};

exports.checkToken = (req, res, next) => {
  authService.checkToken(req.query.token,
    (err, result) => {
      if (err) {
        return res.status(401).send({
          ok: false,
          error: "Token is invalid or expired"  
        });
      }
      res.status(200).send({ok: "true", user: result});
    }
  );
};

authController模塊實現(xiàn)兩個Express路由:login()用于執(zhí)行登錄操作并返回相應的token,checkToken()用于檢查token的有效性。這兩個路由委托他們的大部分邏輯到authService,所以他們唯一的工作是處理HTTP請求和響應。

app模塊

最后,在應用程序的入口點,我們調(diào)用我們的controller。遵循約定,我們將把這個邏輯放在名為app.js的模塊中,放在我們項目的根目錄下,如下所示:

"use strict";

const Express = require("express");
const bodyParser = require("body-parser");
const errorHandler = require("errorhandler");
const http = require("http");

const authController = require("./lib/authController");

let app = module.exports = new Express();
app.use(bodyParser.json());

app.post("/login", authController.login);
app.get("/checkToken", authController.checkToken);

app.use(errorHandler());
http.createServer(app).listen(3000, () => {
  console.log("Express server started");
});

我們可以看到,我們的應用程序模塊是非?;A(chǔ)的。 它包含一個簡單的Express服務器,它注冊了一些中間件和authController導出的兩條路由。這也就是一個簡單的包含controllermodelWeb服務,添加好前端HTML頁面,也就實現(xiàn)了MVC架構(gòu)的分離

模式的特征

模式闡述了在特定設(shè)計情形下反復出現(xiàn)的問題,并提供了解決方案。

模式記錄了已得到充分證明的既有設(shè)計經(jīng)驗。

模式描述了超越類、實例和組件的抽象。

模式提供了一種通用語言,并讓大家對設(shè)計原則有一致的認識。

模式是一種記錄軟件架構(gòu)的手段。

模式有助于創(chuàng)建具有指定特征的軟件。

模式有助于打造復雜而異質(zhì)的軟件架構(gòu)。

模式有助于控制軟件的復雜度。

為什么叫模式

每個模式都包含三部分:

背景(Context) 問題出現(xiàn)的背景;

問題(Problem) 該背景下反復出現(xiàn)的問題;

解決方案(Solution) 經(jīng)過實踐檢驗的解決之道。

背景

背景描繪了問題發(fā)生的情形,讓原本平淡無奇的問題—解決方案更為豐滿。模式的背景可能非常籠統(tǒng),如“開發(fā)帶人機界面的軟件”,也可能將具體的模式聯(lián)系在一起,如“在模型、視圖和控制器之間實現(xiàn)變更傳播機制”。

問題

模式描述綱要的這部分闡述了給定背景下反復出現(xiàn)的問題。它以籠統(tǒng)的問題陳述開始,闡述了問題的本質(zhì):必須解決的具體設(shè)計問題是什么?例如,Model-View-Controller模式解決的是用戶界面頻繁變更的問題。模式表示解決問題時需要考慮的方方面面:

解決方案必須滿足的需求,如進程之間的對等通信必須高效;

必須考慮的約束條件,如進程間通信必須遵守特定協(xié)議;

解決方案必須具備的特征,如應該能夠輕松地修改軟件。

Model-View-Controller模式說明了兩種作用力:修改用戶界面應輕而易舉,且這種修改不應影響軟件的核心功能。

解決方案

模式的解決方案部分指出了如何解決反復出現(xiàn)的問題,更準確地說是如何平衡相關(guān)的作用
力。在軟件架構(gòu)中,這樣的解決方案包括兩個方面:

每個模式都指定了特定的結(jié)構(gòu),即元素的空間配置。例如,Model-View-Controller模式的描述中有這樣一句話:“將交互式應用程序分成三部分——處理、輸出和輸入。”

每個模式都說明了運行階段的行為。例如,在Model-View-Controller模式的“解決方案”部分有這樣一句話:“控制器接受輸入,這通常是表示鼠標移動、鼠標按鈕激活或鍵盤輸入的事件。事件被轉(zhuǎn)換為服務請求,而服務請求要么被發(fā)送給模型,要么被發(fā)送給視圖?!?/p> 模式的類型

模式一般分為三類:

架構(gòu)模式:具體軟件架構(gòu)的模板,描繪了應用程序的系統(tǒng)級結(jié)構(gòu)特征,并將影響子系統(tǒng)的架構(gòu)。例如Model-View-Controller模式

設(shè)計模式:是一種中型模式,規(guī)模比架構(gòu)模式小,但通常獨立于編程語言和編程范式。應用設(shè)計模式不會影響軟件系統(tǒng)的基本架構(gòu),但可能嚴重影響子系統(tǒng)的架構(gòu)。例如:觀察者模式。

成例:如何解決特定的設(shè)計問題。針對于特定的語言的模式。例如C++語言的Counted Body模式。

總結(jié)

模式提供了一種前途無量的方法,可用于開發(fā)具有指定特征的軟件。它們記錄了既有的設(shè)計知識,有助于找到設(shè)計問題的妥善解決方案。模式的規(guī)模和抽象程度各異,涵蓋了眾多重要的軟件開發(fā)領(lǐng)域。模式彼此交織在一起,我們可以使用一個模式來改善另一個更大的模式,還可結(jié)合使用多個模式來解決復雜的問題。模式論述了軟件架構(gòu)的一些重要方面,并給既有技術(shù)和方法提供了補充。模式可以和任何編程范式結(jié)合使用,且?guī)缀蹩墒褂萌魏尉幊陶Z言實現(xiàn)。

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/92438.html

相關(guān)文章

  • 全棧開發(fā)自學路線

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

    galaxy_robot 評論0 收藏0
  • 全棧開發(fā)自學路線

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

    Scorpion 評論0 收藏0
  • Web框架常用架構(gòu)模式(JavaScript語言)

    摘要:只能在不同的時候選用不同的假設(shè)和不同的理論來解釋問題,許來西的文章講到科學一定程度上通過放棄一貫性換取了實用性,放棄自洽性換取了它洽性。然而遺憾的是本身只提供了模塊和洋蔥模型的最小封裝。 在寫干貨之前,我想先探(qiang)討(diao)兩個問題,模式的局限性?模式有什么用? 最近看到一篇文章對我啟發(fā)很大,許來西在知乎的回答《哲學和科學有什么關(guān)聯(lián)?》,全篇較長,這里摘錄我要引出的一點:...

    loostudy 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<