Node.js设计模式笔记
发布于 6 年前 作者 18820227745 2921 次浏览 来自 分享

看了《代码整洁之道-程序员的职业素养》后,知道要些写好代码要把设计模式给学好。看了《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
    const EventEmitter = require('events');
    module.exposts = class Roee extends EventEmitter {
    	constructor (executor) {
    		super();
    		const emit = this.emit.bind(this);
    		this.emit = undefined;
    		executor(emit);
    	}
    };
    
    ticker.js
    const Roee = require('./roee');
    const ticker = new Roee((emit) => {
    	let tickCount = 0;
    	setInterval(() => emit('tick', tickCount++), 1000);
    });
    module.exports = ticker;
    
    index.js
    const ticker = require('./ticker');
    ticker.on('tick', (tickCount) => console.log(tickCount, 'TICK'));
    // ticker.emit('something', {}) <-- This will fail
    

3. 代理模式

  • 简介: 代理是用来控制对另一个对象(本体)访问的对象。它实现了与本体对象相同的接口,我们可以对两个对象进行随意的替换使用,这种设计模式就是代理模式,也称作代替模式。
  • 场景:
    • 数据验证:代理对象在讲输入传递给本体对象之前进行验证
    • 安全性:代理对象会校验客户端是否被授权对本体对象执行操作,只有通过校验了,操作的请求才会被传递到本体对象。
    • 缓存:代理对象内部唯一一个缓存系统,只有当需要使用的数据当前不在缓存中时,才会将需要执行的操作传递到本体对象。
    • 延迟初始化:如果本体对象的创建时非常耗费时间和空间的,代理对象可以延迟其创建的时机,知道真正需要时。
    • 日志:代理对象拦截调用的方法和相关参数,并将他们记录下来。
    • 远程对象代理:代理对象可以为远程对象提供本地的代表,就像使用一个本地的对象。
  • 实现:
    • 对象组合:一个对象为了扩展其自身的功能或者使用其他对象的功能,将另一个对象合并进来。
      • 实例:使用伪类和工厂方法
      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;
      
      解释:拦截了我们感兴趣的操作方法(比如hello()方法),而将剩下的方法委托给本体对象。该代码维护了原型链,保证了代理对象和本体对象的一致性。
      • 不使用继承的方法实现
      function createProxy(subject) {
      	return {
      		// proxied method
      		hello: () => (subject.hello(), ' world!'),
      		// delegated method
      		goodbye: () => (subject.goodbye.apply(subject, arguments))
      	};
      }
      
      将大多数对象委托给本体对象的库–delegates
    • 对象增强:通过替换本体对象方法的方式来实现代理
      • 实例:
      function createProxy(subject) {
      	const helloOrig = subject.hello;
      	subject.hello = () => (helloOrig.call(this) + 'world! ');
      	return subject;
      }
      

4. 装饰者模式

5. 适配器模式

6. 策略模式

7. 状态模式

8. 中间件模式

9. 命令模式

^_^未完待续

4 回复

为什么不用es6?

@chapgaga 有些不明白你的意思

@chapgaga 你说的是用class继承,不过有时构建比较复杂的类时比较复杂,用stampit().compose拼装更加直观。

回到顶部