常用的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
- 英文原文 https://blog.risingstack.com/fundamental-node-js-design-patterns/
</ol> 來自:http://wwsun.me/posts/node-design-patterns.html