Node.js设计模式笔记
看了《代码整洁之道-程序员的职业素养》后,知道要些写好代码要把设计模式给学好。看了《Node.js设计模式》给大家分享一波。
设计模式:是针对经常出现的问题的可重用解决方案。
1.工厂模式
-
简介
- 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式
-
实例
// 创建一个Image对象
function createImage(name) {
return new Image(name);
}
const image = createImage('photo.jpeg');
- 进阶 可组合的工厂函数
- 简介: 一类特殊的工厂函数,它们可以被组合到一起来构建新的增强的工厂函数
- 实例:创建一个视频游戏,游戏中的角色有各种行为: 他们可以在屏幕上移动,可以砍杀和射击。当然,一个觉设应该有一些基础的属性,比如生命点数,在屏幕上的位置和姓名。
- 定义几个角色,每一种都有各自的行为:
- Character: 基础角色,拥有生命点数、位置信息和姓名。
- Mover: 能够移动的角色。
- Slasher: 能够砍杀的角色。
- Shooter: 能够射击的角色(只要子弹充足)。
- 组合定义新的角色:
- Runner:能够移动的角色。
- Samurai: 能够移动和砍杀的角色。
- Sniper: 能够射击的角色(但是无法移动)。
- Cunslinger: 能够移动和射击的角色。
- Western Samurai: 能够移动、砍杀和射击的角色。
- 定义几个角色,每一种都有各自的行为:
- 实现代码:
const stampit = require('stampit');
const character = stampit().
props({
name: 'anonymous',
lifePoints: 100,
x: 0,
y: 0,
});
const mover = stampit()
.methods({
move(xIncr, yIncr) {
this.x += xIncr;
this.y += yIncr;
console.log(`${this.name} moved to [${this.x}, ${this.y}]`);
}
});
const slasher = stampit()
.methods({
slash(direction) {
console.log(`${this.name} slashed to the ${direction}`);
}
});
const shooter = stampit()
.props({
bullets: 6,
})
.methods({
shoot(direction) {
if (this.bullets > 0) {
-- this.bullets;
console.log(`${this.name} shoot to the ${direction}`);
}
}
});
// 组合工厂函数
const runner = stampit().compose(character, mover);
const samurai = stampit().compose(character, mover, slasher);
const sniper = stampit().compose(character, shooter);
const gunslinger = stampit().compose(character, mover, shooter);
const westernSamurai = stampit().compose(gunslinger, samurai);
// 使用
const gojiro = westernSamurai();
gojiro.name = 'Gojiro kiryu';
gojiro.move(1, 0);
gojiro.slash('left');
gojiro.shoot('right');
- 扩展: 工厂模式的模块代码学习
- 扩展:可组合工厂函数模块
2. 揭示构造器模式
- 简介:构造器模式中的对象的属性是通过一个构造器来设置的,最后返回一个不同属性的对象。接受一个函数作为构造函数的参数。
- 实例:
- Promise的构造函数
const promise = new Promise(function (resolve, reject) { // ...... });
- 构建一个只读事件触发器 roee.js
ticker.jsconst EventEmitter = require('events'); module.exposts = class Roee extends EventEmitter { constructor (executor) { super(); const emit = this.emit.bind(this); this.emit = undefined; executor(emit); } };
index.jsconst Roee = require('./roee'); const ticker = new Roee((emit) => { let tickCount = 0; setInterval(() => emit('tick', tickCount++), 1000); }); module.exports = ticker;
const ticker = require('./ticker'); ticker.on('tick', (tickCount) => console.log(tickCount, 'TICK')); // ticker.emit('something', {}) <-- This will fail
3. 代理模式
- 简介: 代理是用来控制对另一个对象(本体)访问的对象。它实现了与本体对象相同的接口,我们可以对两个对象进行随意的替换使用,这种设计模式就是代理模式,也称作代替模式。
- 场景:
- 数据验证:代理对象在讲输入传递给本体对象之前进行验证
- 安全性:代理对象会校验客户端是否被授权对本体对象执行操作,只有通过校验了,操作的请求才会被传递到本体对象。
- 缓存:代理对象内部唯一一个缓存系统,只有当需要使用的数据当前不在缓存中时,才会将需要执行的操作传递到本体对象。
- 延迟初始化:如果本体对象的创建时非常耗费时间和空间的,代理对象可以延迟其创建的时机,知道真正需要时。
- 日志:代理对象拦截调用的方法和相关参数,并将他们记录下来。
- 远程对象代理:代理对象可以为远程对象提供本地的代表,就像使用一个本地的对象。
- 实现:
- 对象组合:一个对象为了扩展其自身的功能或者使用其他对象的功能,将另一个对象合并进来。
- 实例:使用伪类和工厂方法
解释:拦截了我们感兴趣的操作方法(比如hello()方法),而将剩下的方法委托给本体对象。该代码维护了原型链,保证了代理对象和本体对象的一致性。function createProxy(subject) { const proto = Object.getPrototypeOf(subject); function Proxy(subject) { this.subject = subject; }; Proxy.prototype = Object.create(proto); // proxied method Proxy.prototype.hello = function() { return this.subject.hello() + ' world!'; }; // delegated method Proxy.prototype.goodbye = function() { return this.subject.goodbye .apply(this.subject, arguments); }; return new Proxy(subject); } modult.exports = createProxy;
- 不使用继承的方法实现
将大多数对象委托给本体对象的库–delegatesfunction createProxy(subject) { return { // proxied method hello: () => (subject.hello(), ' world!'), // delegated method goodbye: () => (subject.goodbye.apply(subject, arguments)) }; }
- 对象增强:通过替换本体对象方法的方式来实现代理
- 实例:
function createProxy(subject) { const helloOrig = subject.hello; subject.hello = () => (helloOrig.call(this) + 'world! '); return subject; }
- 对象组合:一个对象为了扩展其自身的功能或者使用其他对象的功能,将另一个对象合并进来。
4. 装饰者模式
5. 适配器模式
6. 策略模式
7. 状态模式
8. 中间件模式
9. 命令模式
^_^未完待续
4 回复
为什么不用es6?
@chapgaga 有些不明白你的意思
@18820227745 用es6写模式啊
@chapgaga 你说的是用class继承,不过有时构建比较复杂的类时比较复杂,用stampit().compose
拼装更加直观。