最近终于看完买了很久的《Javascript设计模式与开发实践》,感觉还是受益匪浅的。 在这里做了一个简单的小结,将书上提到的设计模式尽量用自己的思路写出来,当然也是有所借鉴。书上的代码都是基于ES5的,本次小结会用到ES6来写。 感觉应该还是蛮多错漏的,欢迎指正。
单例模式(Singleton pattern)
确保一个类只有一个实例,并提供对该实例的全局访问。
function createSingleton(construct) {
let storage = null;
let handle = {
construct: function(trapTarget, argumentList) {
if (!storage) {
storage = new trapTarget(argumentList[0]);
}
return storage;
},
};
return new Proxy(construct, handle);
}
class Singleton {
constructor(params) {
this.val = params;
}
getVal() {
console.log(this.val);
}
setVal(params) {
this.val = params;
}
}
// run
let ProxySingleton = createSingleton(Singleton);
let singletonObj_1 = new ProxySingleton(123);
let singletonObj_2 = new ProxySingleton(456);
console.log(singletonObj_1 === singletonObj_2); // true
复制代码
策略模式(Strategy pattern)
指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
const Strategy = {
A(params) {
console.log('Execute strategy A!', params);
},
B(params) {
console.log('Execute strategy B!', params);
},
C(params) {
console.log('Execute strategy C!', params);
},
};
const StrategyExecute = function(params) {
const { type, val } = params;
return Strategy[type](val);
};
// run
StrategyExecute({ type: 'A', val: 123 });
StrategyExecute({ type: 'B', val: 456 });
StrategyExecute({ type: 'C', val: 789 });
复制代码
代理模式(Proxy pattern)
为其他对象提供一个代理以控制对这个对象的访问。
let game = {
play() {
console.log('Play!');
},
};
let gameMachine = {
token: 0,
play: new Proxy(game.play, {
apply(proxyTag, proxyThis, args) {
if (proxyThis.token > 0) {
proxyThis.token--;
return Reflect.apply(proxyTag, proxyThis, args);
} else {
console.warn('No token!')
}
},
})
};
// run
gameMachine.play(); // No token!
gameMachine.token = 1;
gameMachine.play(); //Play!
gameMachine.play(); // No token!
复制代码
迭代器模式(Iterator pattern)
提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
// 迭代器
function Iterator(params) {
// 创建迭代器
let iterator = params();
// 开始迭代
let stepResult = iterator.next();
if (!stepResult.done) {
// 定义下一步操作的方法,并执行
(function step() {
if (!stepResult.done) {
if (typeof stepResult.value === 'function') {
(async function() {
let stepResultData = await stepResult.value();
stepResult = iterator.next(stepResultData);
step();
})();
} else {
stepResult = iterator.next(stepResult.value);
step();
}
}
})();
}
}
// 迭代步骤
function fetchData() {
// ajax get some data
return [
{
id: 1,
name: 'test1',
},
{
id: 2,
name: 'test2',
}
];
}
function resolveData(params) {
// rebuild data
return params.map(item => item.name);
}
let iteratorList = function *() {
const apiData = yield fetchData();
const list = yield resolveData(apiData);
yield console.log(list);
};
// run
Iterator(iteratorList);
复制代码
观察者模式(Observer pattern)
发布-订阅模式(Publish–subscribe pattern)
在对象间定义一个一对多的联系性,由此当一个对象改变了状态,所有其他相关的对象会被通知并且自动刷新。
let Event = {
_events: {},
on(event, fn) {
if (Array.isArray(event)) {
event.forEach((e) => { this.on(e, fn) });
} else {
(this._events[event] || (this._events[event] = [])).push(fn);
}
},
once(event, fn) {
function on () {
this.off(event, on);
fn.apply(this, arguments);
}
on.fn = fn;
this.on(event, on);
},
off(event, fn) {
if (!arguments.length) {
this._events = Object.create(null);
return true;
}
if (Array.isArray(event)) {
event.forEach((e) => { this.off(e, fn) });
return true;
}
let eventFns = this._events[event];
if (!eventFns) {
return false;
}
if (!fn) {
this._events[event] = null;
return true;
}
if (fn) {
let eventFn;
let len = eventFns.length;
while (len--) {
eventFn = eventFns[len];
if (eventFn === fn || eventFn.fn === fn) {
eventFns.splice(len, 1);
break;
}
}
return true;
}
},
emit(event) {
let eventFns = this._events[event];
if (eventFns) {
let [ , ...rest ] = arguments;
eventFns.forEach((fn) => {
try {
fn.apply(this, rest);
} catch (err) {
console.error(`Error: event handler for "${event}"`, err, this);
}
});
}
}
};
// run
Event.once('testEventBus', () => { console.log('Event had emitted.'); });
Event.emit('testEventBus'); // Event had emitted.
复制代码
命令模式(Command pattern)
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。
class FanMachine {
constructor() {
this._commands = [];
};
execute(command, ...rest) {
this._commands.push(command);
command.execute(...rest);
}
}
class Fan {
static turnOn() {
console.log('开启');
};
static turnOff() {
console.log('关闭');
};
static windSpeed(params) {
console.log('风速:', params);
};
}
class setCommand {
constructor(fn) {
this.execute = fn;
}
}
// run
let fanCommandTurnOn = new setCommand(Fan.turnOn);
let fanCommandTurnOff = new setCommand(Fan.turnOff);
let fanCommandWindSpeed = new setCommand(Fan.windSpeed);
let fanMachine = new FanMachine();
fanMachine.execute(fanCommandTurnOn); // 开启
fanMachine.execute(fanCommandWindSpeed, 1); //风速:1
fanMachine.execute(fanCommandWindSpeed, 2); //风速:2
fanMachine.execute(fanCommandWindSpeed, 3); //风速:3
fanMachine.execute(fanCommandTurnOff); // 关闭
复制代码
组合模式(Composite pattern)
把多个对象组成树状结构来表示局部与整体,这样用户可以一样的对待单个对象和对象的组合。
class Composite {
constructor() {
this._commands = [];
}
add(command) {
this._commands.push(command);
}
execute() {
this._commands.forEach((command) => { command.execute(); })
}
}
let commandA = {
execute() {
console.log('Execute A!');
}
};
let commandB = {
execute() {
console.log('Execute B!');
}
};
let commandC = {
execute() {
console.log('Execute C!');
}
};
let commandD = new Composite();
commandD.add(commandB);
commandD.add(commandC);
let commandCenter = new Composite();
commandCenter.add(commandA);
commandCenter.add(commandD);
// run
commandCenter.execute();
// Execute A!
// Execute B!
// Execute C!
复制代码
模板方法模式(Template method pattern)
模板方法模式准备一个抽象类,将部分逻辑以具体方法及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先构建一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。
class MakeDrink {
constructor(name) {
this._drinkName = name;
}
boilWater() {
console.log('煮沸水');
}
pourInCup() {
console.log('加原料');
}
brew() {
console.log('冲泡');
}
addCondiments() {
console.log('加调料');
}
init() {
this.boilWater();
this.pourInCup();
this.brew();
this.addCondiments();
}
}
class MakeLemonTea extends MakeDrink {
pourInCup() {
console.log('加茶叶');
}
addCondiments() {
console.log('加柠檬和糖');
}
}
// run
let lemonTea = new MakeLemonTea('柠檬茶');
lemonTea.init();
// 煮沸水
// 加茶叶
// 冲泡
// 加柠檬和糖
复制代码
享元模式(Flyweight pattern)
通过共享以便有效的支持大量细颗粒对象。
// ...
复制代码
职责链模式(Chain-of-responsibility Pattern)
为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
class Chain {
constructor(fn) {
this._fn = fn;
this._next = null;
}
setNext(next) {
return this._next = next;
}
pass(...args) {
let ret = this._fn.apply(this, args);
if (ret === 'pass') {
return this._next && this._next.pass.apply(this._next, args);
}
return ret;
}
next(...args) {
return this._next && this._next.pass.apply(this._next, args);
}
}
let first = new Chain(function(params) {
console.log('first: ', params);
this.next(2);
});
let second = new Chain(function(params) {
console.log('second: ', params);
return 'pass';
});
let third = new Chain(function(params) {
console.log('third: ', params);
this.next(4);
});
let last = new Chain(function(params) {
console.log('last: ', params);
return false;
});
first.setNext(second).setNext(third).setNext(last);
// run
first.pass(1);
// first: 1
// second: 2
// third: 2
// last: 4
复制代码
中介者模式(Mediator pattern)
包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。
// ...
复制代码
装饰器(修饰)模式(Decorator Pattern)
向某个对象动态地添加更多的功能。修饰模式是除类继承外另一种扩展功能的方法。
class Decorator {
constructor(params) {
const {value, configurable, enumerable, writable} = params;
this.value = value && typeof value === 'function' ? value : null;
this.configurable = configurable || false;
this.enumerable = enumerable || false;
this.writable = writable || false;
}
static create(obj, prop, descriptor) {
if (descriptor.value && typeof descriptor.value === 'function') {
let origin = obj[prop];
delete obj[prop];
descriptor.value = descriptor.value(origin);
Object.defineProperty(obj, prop, descriptor);
}
}
}
let decoratorTest = {
name: 'test',
init() {
Decorator.create(this, 'func', new Decorator({
value: function (fn) {
return function () {
// do something before...
console.log('before!');
fn.apply(this, arguments);
// do something after...
console.log('after!');
}
}
}));
console.log('init.');
},
func(...params) {
console.log('decoratorTest: ', ...params);
},
};
// run
decoratorTest.func(123);
decoratorTest.init();
decoratorTest.func(456);
// decoratorTest: 123
// init.
// begin!
// decoratorTest: 456
// end!
复制代码
状态模式(State pattern)
class State {
constructor(params) {
return State.create(this, params)
}
setState(state) {
this.current = state;
this.storage.push(state);
}
next() {
const { name: currName, to: currTo } = this.main[this.current];
if (currTo) {
const nextName = this.main[currTo].name;
const {beforeLeave} = this.hock[currName];
const {beforeEnter, onMount} = this.hock[nextName];
if (beforeLeave) { beforeLeave(); }
this.setState(currTo);
if (beforeEnter) { beforeEnter(); }
if (onMount) { onMount(); }
}
return this.current;
}
previous() {
return this.goBack(1);
}
goBack(num) {
const storage = this.storage;
const len = storage.length;
if (len > 1) {
if (len > num) {
this.current = storage[len - num -1];
this.storage = storage.slice(0, len - num);
} else {
this.current = storage[0];
this.storage = [storage[0]];
}
}
return this.current;
}
reset() {
return this.goBack(this.storage.length - 1);
}
addHock(stateName, event, fn) {
this.hock[stateName][event] = fn;
}
on(stateName, fn) {
this.addHock(stateName, 'onMount', fn);
}
beforeEnter(stateName, fn) {
this.addHock(stateName, 'beforeEnter', fn);
}
beforeLeave(stateName, fn) {
this.addHock(stateName, 'beforeLeave', fn);
}
static create(_this, params) {
const { initial, transitions, methods } = params;
_this.current = initial;
_this.storage = [initial];
_this.main = {};
_this.hock = {};
transitions.forEach((e) => {
const { name, from, to } = e;
// main
_this.main[from] = {};
_this.main[from].name = name;
_this.main[from].to = to;
// hock
_this.hock[name] = {};
_this.hock[name].from = from;
_this.hock[name].to = to;
_this.hock[name].beforeEnter = methods[`beforeEnter${State._firstUpperCase(name)}`] || null;
_this.hock[name].onMount = methods[`on${State._firstUpperCase(name)}`] || null;
_this.hock[name].beforeLeave = methods[`beforeLeave${State._firstUpperCase(name)}`] || null;
// event
_this[name] = function () {
const currStateName = _this.main[this.current].name;
if (name !== currStateName) {
const { beforeLeave } = _this.hock[currStateName];
const { from, beforeEnter, onMount } = _this.hock[name];
if (beforeLeave) { beforeLeave(); }
_this.setState.call(_this, from);
if (beforeEnter) { beforeEnter(); }
if (onMount) { onMount(); }
return from;
} else {
return this.current;
}
}
});
return _this;
}
static _firstUpperCase(str) {
const [first, ...rest] = str;
return `${first.toUpperCase()}${rest.join('')}`;
}
}
const green = 'green';
const yellow = 'yellow';
const red = 'red';
let fsm = new State({
initial: green,
transitions: [
{
name: 'greenLight',
from: green,
to: yellow,
},
{
name: 'yellowLight',
from: yellow,
to:red,
},
{
name: 'redLight',
from: red,
to: green,
},
],
methods: {
onGreenLight() { console.log('绿灯'); },
onYellowLight() { console.log('黄灯'); },
onRedLight() { console.log('红灯'); },
}
});
// run
// 初始化状态为 green
fsm.next(); // 黄灯
fsm.next(); // 红灯
fsm.next(); // 绿灯
fsm.previous(); // return 'red'
fsm.greenLight(); // 绿灯
fsm.yellowLight(); // 黄灯
fsm.redLight(); // 红灯
复制代码
设配器模式(Adapter pattern)
将某个类的接口转换成客户端期望的另一个接口表示。适配器模式可以消除由于接口不匹配所造成的类兼容性问题。
// ...
复制代码