常用的Node.js設計模式

jopen 9年前發布 | 40K 次閱讀 Node.js Node.js 開發

當我們談到設計模式的時候,你很可能會想到單例模式、觀察者模式、工廠模式。本文并不會僅僅局限于介紹這些在Node編程中常見的設計模式,而且還會涉及到依賴注入、中間件等功能的介紹。

什么是設計模式

A design pattern is a general, reusable solution to a commonly occurring problem.

</blockquote>

單例模式

單例模式將“類”的實例的個數限制為一個。在Node.js中創建單例模式非常的簡單,只需要用require即可。

//area.js
var PI = Math.PI;

function circle (radius) {
return radius radius PI; }

module.exports.circle = circle;</pre>

無論你在應用中require這個模塊多少次,這個模塊的實例只會有一份存在。

var areaCalc = require('./area');
console.log(areaCalc.circle(5));

正因為require的這種行為,單例模式很可能是NPM模塊中最常見的Node.js設計模式。

觀察者模式

一個對象維護著一個依賴/觀察者列表,并在狀態改變的時候自動的通知列表中的每個成員。要實現觀察者模式,可以借助于EventEmitter。

// MyFancyObservable.js
var util = require('util');
var EventEmitter = require('events').EventEmitter;

function MyFancyObservable() {
EventEmitter.call(this); }

util.inherits(MyFancyObservable, EventEmitter);</pre>

這樣我們就創建了一個可被觀察的對象。為了讓它更有用,我們可以為它增加點功能:

MyFancyObservable.prototype.hello = function (name) {  
  this.emit('hello', name);
};

太好了,現在我們的觀測者可以發出事件(emit event)了,讓我們來試下:

var MyFancyObservable = require('MyFancyObservable');
var observable = new MyFancyObservable();

observable.on('hello', function (name) {
console.log(name); });

observable.hello('john');</pre>

工廠模式

工廠模式使我們不需要使用構造器,而是通過提供一個泛型(通用)接口來創建對象。這種模式在創建過程變得復雜時會非常有用。

function MyClass (options) {
this.options = options; }

function create(options) {
// modify the options here if you want return new MyClass(options); }

module.exports.create = create;</pre>

工廠也使得測試變得更加簡單,因為你可以通過這種模式來注入模塊的依賴。

依賴注入

Dependency injection is a software design pattern in which one or more dependencies (or services) are injected, or passed by reference, into a dependent object.

</blockquote>

在下面的例子中,我們將創建一個獲取數據庫依賴的UserModel類。

function userModel (options) {
var db;

if (!options.db) { throw new Error('Options.db is required'); }

db = options.db;

return { create: function (done) { db.query('INSERT ...', done); } } }

module.exports = userModel;</pre>

然后,我們可以使用如下方法創建實例:

var db = require('./db');

var userModel = require('User')({
db: db });</pre>

為什么這很有用?因為這使得測試變得簡單,當你寫單元測試的時候,你可以很容易的注入一個假db對象到你的模型中。

Middlewares/ pipelines

中間件的概念很簡單但卻非常強大:一個單元/函數的輸出是下一個的輸入。如果你曾用過Express或Koa那么你肯定接觸過。

我們來看看在Koa中是怎么做的:

app.use = function(fn){  
  this.middleware.push(fn);
  return this;
};

也就是說,當你使用一個中間件的時候,它會被push到middleware數組中,這非常的贊,但是當請求到達服務器的時候發生了什么呢?

var i = middleware.length;  
while (i--) {  
  next = middleware[i].call(this, next);
}

原來沒什么神奇的地方,你的中間件只不過是依次被循環遍歷的調用了而已。

Streams

你可以將流想象成一個特殊的管道。它們更擅長處理大量的流動數據,即使是它們是字節而不是對象。

process.stdin.on('readable', function () {  
    var buf = process.stdin.read(3);
    console.dir(buf);
    process.stdin.read(0);
});

調用

$ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | node consume2.js 
<Buffer 61 62 63>  
<Buffer 0a 64 65>  
<Buffer 66 0a 67>  
<Buffer 68 69 0a>

有一本好書你可以參考一下:NodeJS Stream Handbook

References

  1. 英文原文 https://blog.risingstack.com/fundamental-node-js-design-patterns/
  2. </ol> 來自:http://wwsun.me/posts/node-design-patterns.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!