近日,重新学习梳理了JS设计模式,特地在这里做下笔记记录下。
迭代器模式
特征
- 顺序访问集合
- 使用者无需知道内部集合结构
代码
class Iterator {
constructor(container) {
this.list = container.list;
this.index = 0;
}
next() {
if (this.hasNext()) {
return this.list[this.index++];
}
return null;
}
hasNext() {
if (this.index >= this.list.length) {
return false;
}
return true;
}
}
class Container {
constructor(list) {
this.list = list;
}
// 生成遍历器
getIterator() {
return new Iterator(this);
}
}
let container = new Container([1, 2, 3, 4, 5]);
let iterator = container.getIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}
应用场景
1、ES6 iterator
- ES6 语法中,有序集合的数据类型已经很多
Array、Map、Set、String、TypedArray、arguments、NodeLists - 需要一个统一的遍历接口来遍历所有的数据类型
(注意,object 不是有序集合,可以用 Map 替代) - 以上数据类型,都有[Symbol.iterator]属性
- 属性值是函数,执行函数返回一个迭代器
- 这个迭代器有 next 方法可顺序迭代子元素
- 可运行 Array.prototype[Symbol.iterator]来测试
function each(data) {
// 生成遍历器
let iterator = data[Symbol.iterator]();
// console.log(iterator.next()); 有数据返回{value:1,done:false}
// console.log(iterator.next()); 没有数据返回{value:undefined,done:true}
let item = { done: false };
while (!item.done) {
item = iterator.next();
if (!item.done) {
console.log(item.value);
}
}
}
// 测试代码
let arr = [1, 2, 3];
let nodeList = document.getElementByTagName("p");
let m = new Map();
m.set("a", 100);
m.set("b", 200);
each(arr);
each(nodeList);
each(m);
// 'Symbol.iterator' 并不知道人人都知道
// 也不是每个人都需要封装个each方法
// 因此有了 'for...of' 语法
function each(data) {
// data 要有symbol.iterator 属性
for (let item of data) {
console.log(item);
}
}
each(arr);
each(nodeList);
each(m);
状态模式
特点
- 一个对象有状态变化
- 每次状态变化都会触发一个逻辑
- 不能总是用 if...else...来控制
- 主体里面可以获取状态的信息,状态的切换和状态的获取 是分开的
代码
// 状态(红灯、黄灯、绿灯)
class State {
constructor(color) {
this.color = color;
}
handle(context) {
console.log(`turn to ${this.color} light`);
context.setState(this);
}
}
// 主体
class Context {
constructor() {
this.state = null;
}
getState() {
return this.state;
}
setState(state) {
this.state = state;
}
}
//test
let context = new Context();
let green = new State("green");
let red = new State("red");
let yellow = new State("yellow");
green.handle(context);
context.getState();
red.handle(context);
context.getState();
yellow.handle(context);
context.getState();
应用场景
1、手写一个 promise
// 状态机模型
import StateMachine from "javascript-state-machine";
let fsm = new StateMachine({
init: "pending",
transitions: [
{
name: "resolve",
from: "pending",
to: "fullfilled"
},
{
name: "reject",
from: "pending",
to: "rejected"
}
],
methods: {
// 监听resolve
onResolve: function(state, data) {
// state--当前状态机实例;data--fsm.resolve(xxx)传递的参数
data.successList.forEach(fn => fn());
},
// 监听reject
onReject: function(state, data) {
// state--当前状态机实例;data--fsm.resolve(xxx)传递的参数
data.failList.forEach(fn => fn());
}
}
});
// 定义一个Promise
class MyPromise {
constructor(fn) {
this.successList = [];
this.failList = [];
fn(
function() {
// resolve函数
fsm.resolve(this);
},
function() {
// reject 函数
fsm.reject(this);
}
);
}
then(successFn, failFn) {
this.successList.push(successFn);
this.failList.push(failFn);
}
}
function loadImg() {
const promise = new Promise(function(resolve, reject) {
let img = document.createElement("img");
img.onload = function() {
resolve(img);
};
img.onerror = function() {
reject();
};
img.src = src;
});
return promise;
}
let src = "https://www.baidu.com/img/a.png";
let result = loadImg(src);
result.then(
function() {
console.log("ok1");
},
function() {
console.log("fail1");
}
);
result.then(
function() {
console.log("ok2");
},
function() {
console.log("fail2");
}
);
原型模式
特点
- 类似 clone,因为有的场景使用 new 不合适
应用场景
// 一个原型对象
const prototype = {
getName: function() {
return this.first + " " + this.last;
},
say: function() {
alert("hello");
}
};
// 基于原型对象 创建x
let x = Object.create(prototype);
x.first = "A";
x.last = "B";
alert(x.getName());
x.say();
// 基于原型对象 创建y
let y = Object.create(prototype);
y.first = "A";
y.last = "B";
alert(y.getName());
y.say();
桥接模式
特点
- 用于把抽象化与实现化解耦
- 使得二者可以独立变化
代码
class Color {
constructor(name) {
this.name = name;
}
}
class Shape {
constructor(name, color) {
this.name = name;
this.color = color;
}
draw() {
console.log(`${this.color.name} ${this.name}`);
}
}
// test
let red = new Color("red");
let yellow = new Color("yellow");
let circle = new Shape("circle", red);
circle.draw();
let triangle = new Shape("triangle", yellow);
triangle.draw();
组合模式
特点
- 生成树形结构,表示“整体-部分”关系
- 让整体和部分都具有一致的操作方式
应用场景
123
456
{
tag:'div',
attr:{
id:"div1",
class:"container"
},
children:[
{
tag:"p",
attr:{},
children:['123']
},
{
tag:"p",
attr:{},
children:['456']
}
]
}
享元模式
特点
- 共享内存(主要考虑内存,而非效率)
- 相同的数据 共享使用
应用场景
JS 没有太经典案例
策略模式
特点
- 不同策略分开处理
- 避免出现大量 if...else 或者 switch...case...
- 个人理解 就是使用对象来组件策略
应用场景
class User {
constructor(type) {
this.type = type;
}
buy() {
if (this.type === "ordinary") {
console.log("普通用户购买");
} else if (this.type === "member") {
console.log("会员用户购买");
} else if (this.type === "vip") {
console.log("VIP 用户购买");
}
}
}
// 使用--策略模式
class MemberUser {
buy() {
console.log("会员用户购买");
}
}
class VipUser {
buy() {
console.log("vip 购买");
}
}
class OrdinaryUser {
buy() {
console.log("普通用户购买");
}
}
let u1 = new OrdinaryUser();
u1.buy();
let u2 = new MemberUser();
u2.buy();
let u3 = new VipUser();
u3.buy();
模版方式模式
特点
- 将一个 class 中的方法,以一定顺序封装到一个方法
应用场景
class Action {
handle() {
this.handle1();
this.handle1();
this.handle1();
}
handle1() {
console.log("1");
}
handle2() {
console.log("2");
}
handle3() {
console.log("3");
}
}
职责链模式
应用场景
class Action {
constructor(name) {
this.name = name;
this.nextAction = null;
}
setNextAction(action) {
this.nextAction = action;
}
handle() {
console.log(`${this.name} 审批`);
if (this.nextAction !== null) {
this.nextAction.handle();
}
}
}
//测试代码
let a1 = new Action("组长");
let a2 = new Action("经理");
let a3 = new Action("总监");
a1.setNextAction(a2);
a2.setNextAction(a3);
a1.handle();
命令模式
特点
- 执行命令时,发布者和执行者分开
- 中间加入命令对象,作为中转站
代码
class Receive {
exec() {
console.log("执行");
}
}
class Command {
constructor(receiver) {
this.receiver = receiver;
}
cmd() {
console.log("触发命令");
this.receiver.exec();
}
}
class Invoker {
constructor(command) {
this.command = command;
}
invoke() {
console.log("开始");
this.command.cmd();
}
}
//test
//士兵
let soldier = new Receiver();
// 小号手
let trumpeter = new Command(soldier);
// 将军
let general = new Invoker(trumpeter);
general.invoke();
应用场景
- 网页富文本编辑器,浏览器封装了一个命令对象
- document.execCommand('bold');
- document.execCommand('unfo');
备忘录模式
特点
- 随时记录一个对象的状态变化
- 随时可以恢复之前的某个状态(如撤销功能)
代码
// 备忘录模式
class Memento {
constructor(content) {
this.content = content;
}
getContent() {
return this.content;
}
}
//备忘录列表
class CareTaker {
constructor() {
this.list = [];
}
add(memento) {
this.list.push(memento);
}
get(index) {
return this.list[index];
}
}
// 编辑器
class Editor {
constructor() {
this.content = null;
}
setContent(content) {
this.content = content;
}
getContent() {
return this.content;
}
saveContentToMenento() {
return new Memento(this.content);
}
getContentFromMemento() {
this.content = memento.getContent();
}
}
//test
let editor = new Editor();
let careTaker = new CareTaker();
editor.setContent("11");
editor.setContent("22");
careTaker.add(editor.saveContentToMenento()); // 存储备忘录
editor.setContent("33");
careTaker.add(editor.saveContentToMenento()); // 存储备忘录
editor.setContent("44");
console.log(editor.getContent());
editor.getContentFromMenento(careTaker.get(1));
console.log(editor.getContent());
editor.getContentFromMenento(careTaker.get(0));
console.log(editor.getContent());