内容简介:适配器模式可以让我们使用一个不同的接口来访问一个对象的功能。它用来适配一个对象,来让期望一个不同接口的组件可以使用它。如下图所示:Adapter 实际就是 Adaptee 的封装,导出一个不同的接口。如图所示,Adapter 的接口也可以是 Adaptee 中一个或多个方法的组合。 这个模式非常直观,我们直接来看一个例子。我们围绕 LevelUP API 来构建一个适配器,把它变成一个兼容核心 fs 模块的接口。 尤其是,我们将确保每次调用 readFile() 和 writeFile() 都将转成到 db
适配器模式
适配器模式可以让我们使用一个不同的接口来访问一个对象的功能。它用来适配一个对象,来让期望一个不同接口的组件可以使用它。如下图所示:
Adapter 实际就是 Adaptee 的封装,导出一个不同的接口。如图所示,Adapter 的接口也可以是 Adaptee 中一个或多个方法的组合。 这个模式非常直观,我们直接来看一个例子。
从文件系统API使用 LevelUP
我们围绕 LevelUP API 来构建一个适配器,把它变成一个兼容核心 fs 模块的接口。 尤其是,我们将确保每次调用 readFile() 和 writeFile() 都将转成到 db.get() 和 db.put() 的调用;这样我们就可以把 LevelUP 数据库当做简单文件系统操作的一个存储后台。
我们从创建一个名为 fsAdapter.js 的模块开始。我们将从加载依赖开始,然后导出我们将用来构建适配器的 createFsAdapter() 工厂:
var path = require('path'); module.exports = function createFsAdapter(db) { var fs = {}; //... 继续 }
下面,我们来实现工厂内部的 readFile() 函数,并确保它的接口跟 fs 模块的原生接口之一是兼容的:
fs.readFile = function(filename, options, callback) { if (typeof options === 'function') { callback = option; options = {}; } else if (typeof options === 'string') { options = {encoding: options}; } db.get(path.resolve(filename), { //[1] valueEncoding: options.encoding }, function(err, value) { if (err) { if (err.type === 'NotFoundError') { //[2] err = new Error('ENOENT, open \'' + filename + '\''); err.code = 'ENOENT'; err.errno = 34; err.path = filename; } return callback && callback(err); } callback && callback(null, value); //[3] } ); };
在上述代码中,我们必须做一些额外工作确保我们新函数的行为跟原始的 fs.readFile() 函数要尽可能接近。各步骤描述如下:
- 要从 db 类获取一个文件,我们使用 filename 作为索引来调用 db.get(),并确保总是使用它的全路径(通过使用 path.resolve())。我们把数据库使用的 valueEncoding 设置成跟从输入拿到的 encoding 选项相同。
- 如果key在数据库中没找到,我们就使用 ENOENT 作为错误代码来生成一个错误,这个是 fs 模块用来通知一个缺失文件的。其他任何类型的错误都被前转给 callback(我们在这个例子中,只处理了最常见的错误情况)
- 如果 key-value 对被成功从数据库获取,我们将使用 callback 把这些值返回给调用者。
实现粗燥,大致可用。
我们再来实现 writeFile() 函数:
fs.writeFile = function(filename, contents, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } else if (typeof options === 'string') { options = {encoding: options}; } db.put(path.resolve(filename), contents, { valueEncoding: options.encoding }, callback); }
最后,返回 fs 对象就好:
return fs;
我们可以写一个小的测试模块来试一下:
var fs = require('fs'); fs.writeFile('file.txt', 'Hello', function() { fs.readFile('file.txt', {encoding: 'utf8'}, function(err, res) { console.log(res); }); }); // try to read a missing file fs.readFile('missing.txt', {encoding: 'utf8'}, function(err, res) { console.log(err); });
我是不是可以搞一章 fs module 和 Adapter 模式
现在我们可以把 fs 模块换成我们的适配器了,如下:
var levelup = require('level'); var fsAdapter = require('./fsAdapter'); var db = levelup('./fsDB', {valueEncoding: 'binary'}); var fs = fsAdapter(db);
Adapter 模式在跟浏览器共享代码中扮演非常重要的角色。
实践中
现实世界中使用适配器的例子数不胜数,可以去探索和分析下列值得关注的示例:
- 通过各种适配器可以基于各种后台运行的 LevelUP, https://github.com/rvagg/node-levelup/wiki/Modules#storage-back-ends .
- jugglingdb,多数据库ORM,当然也使用了多个适配器来跟不同的数据库适配, http://github.com/1602/jugglingdb/tree/master/lib/adapters .
跟不同的翻译引擎进行适配,跟不同的短信网关进行适配
* 示例的完整实现是 level-filesystem( https://www.npmjs.org/package/level-filesystem)。
从核心 API 里面分组,并和模式结合进行讲解,术道并重。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Single Page Web Applications
Michael Mikowski、Josh Powell / Manning Publications / 2013-9-30 / USD 44.99
Code for most web sites mostly runs on the server. When a user clicks on a link, the site reacts slowly because the browser sends information to the server and the server sends it back again before di......一起来看看 《Single Page Web Applications》 这本书的介绍吧!