设计模式
一、创建型
1、工厂模式
介绍
- 将
new
操作单独封装 - 构造函数和创建者分离
- 减少每次
new
操作 - 符合开放封闭原则
示列
jQuery
$操作符
通过工厂模式返回一个实例
查看代码
javascript
// 构造函数和创建者分离
function Jquery (selector) {
this.selector = document.querySelectorAll(selector)
}
// new操作单独封装
window.$ = function (selector) {
return new Jquery(selector)
}
var p = $('div')
console.log(p)
// 构造函数和创建者分离
function Jquery (selector) {
this.selector = document.querySelectorAll(selector)
}
// new操作单独封装
window.$ = function (selector) {
return new Jquery(selector)
}
var p = $('div')
console.log(p)
2、单例模式
介绍
- 系统中被唯一使用
- 一个类中只有一个实例
- 符合单一性原则
示列
查看代码
javascript
class SingleObject {
showMessage() {
console.log('showMessage', this)
}
}
// 使用自执行函数,创建一个实例
SingleObject.getInstance = (function () {
let instance = null
return function () {
if (!instance) {
instance = new SingleObject()
}
return instance
}
})()
console.log(SingleObject.getInstance() === SingleObject.getInstance())
class SingleObject {
showMessage() {
console.log('showMessage', this)
}
}
// 使用自执行函数,创建一个实例
SingleObject.getInstance = (function () {
let instance = null
return function () {
if (!instance) {
instance = new SingleObject()
}
return instance
}
})()
console.log(SingleObject.getInstance() === SingleObject.getInstance())
3、原型模式
clone自己,生成一个新对象
Object.create
二、结构型
1、适配器模式
介绍
- 封装旧接口
- 符合开放封闭原则
示列
查看代码
javascript
class SpecialRequest {
request() {
return 'old'
}
}
class Request {
constructor() {
// 封装旧接口
this.adptor = new SpecialRequest()
}
request () {
let type = this.adptor.request()
console.log(type)
}
}
new Request().request()
class SpecialRequest {
request() {
return 'old'
}
}
class Request {
constructor() {
// 封装旧接口
this.adptor = new SpecialRequest()
}
request () {
let type = this.adptor.request()
console.log(type)
}
}
new Request().request()
vue中computed
2、装饰器模式
介绍
- 为对象添加新功能
- 将现有对象和装饰器进行分离
- 不改变其原有的结构功能
- 符合开放封闭原则
示列
查看代码
javascript
class Circle {
constructor() {
this.border = 'none'
}
draw() {
console.log('draw Circle', this)
}
}
class Client {
constructor(circle) {
this.circle = circle
}
draw() {
// 添加新功能
this.circle.draw()
this.setBorder(this.circle)
this.circle.draw()
}
setBorder(circle) {
circle.border = '1px'
console.log('setBorder', circle)
}
}
new Client(new Circle()).draw()
class Circle {
constructor() {
this.border = 'none'
}
draw() {
console.log('draw Circle', this)
}
}
class Client {
constructor(circle) {
this.circle = circle
}
draw() {
// 添加新功能
this.circle.draw()
this.setBorder(this.circle)
this.circle.draw()
}
setBorder(circle) {
circle.border = '1px'
console.log('setBorder', circle)
}
}
new Client(new Circle()).draw()
3、代理模式
介绍
- 使用者无权访问目标对象
- 中间加代理,通过代理做授权和控制
- 代理类和目标类分离
- 符合开放封闭原则
示列
查看代码
javascript
class ReadImg {
constructor(fileName) {
this.fileName = fileName
this.loadImg()
}
show() {
console.log('show image', this.fileName)
}
loadImg() {
console.log('load image', this.fileName)
}
}
class ProxyImg {
constructor(fileName) {
this.img = new ReadImg(fileName)
}
show() {
this.img.show()
}
}
new ProxyImg('www.png').show()
class ReadImg {
constructor(fileName) {
this.fileName = fileName
this.loadImg()
}
show() {
console.log('show image', this.fileName)
}
loadImg() {
console.log('load image', this.fileName)
}
}
class ProxyImg {
constructor(fileName) {
this.img = new ReadImg(fileName)
}
show() {
this.img.show()
}
}
new ProxyImg('www.png').show()
场景
- 网页事件代理
- jQuery中$.proxy
- es6 proxy
VS适配器模式
适配器模式:提供一个不同的接口
代理模式:提供一模一样的接口
VS装饰者模式
装饰器模式:扩展功能,原有功能不变且可直接使用
代理模式:针对原有功能,但是有限制或阉割
4、外观模式
- 为子系统的一组接口提供高层接口
- 使用者使用这个高层接口
- 不符合单一原则和开放封闭原则
示列
查看代码
javascript
function bind(ele, type, selector, fn) {
if (fn == null) {
fn = selector
selector = null
}
// ***
}
// 支持两种方式调用
bind('.app', 'click', '.btn', fn)
bind('.app', 'click', fn)
function bind(ele, type, selector, fn) {
if (fn == null) {
fn = selector
selector = null
}
// ***
}
// 支持两种方式调用
bind('.app', 'click', '.btn', fn)
bind('.app', 'click', fn)
5、桥接模式
- 将抽象和实现分离,使两者可以独立变化
6、组合模式
- 生成树形结构,表示“整体-部分”关系
- 让整体和部分都具有一致的操作方式
7、享元模式
介绍
- 共享内存(主要考虑内存,而非效率)
- 相同的数据,共享使用
- 相同的JS可以共享,不同的JS不能共享
- 将相同的部分抽象出来
三、行为型
1、观察者模式
介绍
- 发布&订阅
- 一对多(1或n)
查看代码
javascript
// 主题,接收状态变化,触发每个观察者
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
attach(observer) {
this.observers.push(observer)
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
}
// 观察者,等待被触发
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this)
}
update() {
console.log(`${this.name} update, state: ${this.subject.getState()}`)
}
}
// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)
s.setState(1)
s.setState(2)
s.setState(3)
// 主题,接收状态变化,触发每个观察者
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
attach(observer) {
this.observers.push(observer)
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
}
// 观察者,等待被触发
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this)
}
update() {
console.log(`${this.name} update, state: ${this.subject.getState()}`)
}
}
// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)
s.setState(1)
s.setState(2)
s.setState(3)
应用
- 网页事件绑定
- Promise
- jQuery callbacks
- nodejs自定义事件
查看代码
javascript
const EventEmitter = require('events').EventEmitter
const emitter1 = new EventEmitter()
emitter1.on('some', info => {
console.log('fn1', info)
})
emitter1.on('some', info => {
console.log('fn2', info)
})
emitter1.emit('some', 'xxxx')
const EventEmitter = require('events').EventEmitter
const emitter1 = new EventEmitter()
emitter1.on('some', info => {
console.log('fn1', info)
})
emitter1.on('some', info => {
console.log('fn2', info)
})
emitter1.emit('some', 'xxxx')
- vue和react组件生命周期触发
- vue watch
2、迭代器模式
顺序访问一个集合 使用者无需知道集合的内部结构
查看代码
js
// 迭代器模式
class Iterator {
constructor(container) {
this.list = container.list
this.index = 0
}
hasNext() {
return this.index < this.list.length
}
next() {
if (this.hasNext()) {
return this.list[this.index++]
}
return null
}
}
class Container {
constructor(list) {
this.list = list
}
getGetIterator() {
return new Iterator(this)
}
}
const arr = [100, 99, 3]
const list = new Container(arr)
const generate = list.getGetIterator()
console.log(generate.next())
console.log(generate.next())
console.log(generate.next())
console.log(generate.next())
// 迭代器模式
class Iterator {
constructor(container) {
this.list = container.list
this.index = 0
}
hasNext() {
return this.index < this.list.length
}
next() {
if (this.hasNext()) {
return this.list[this.index++]
}
return null
}
}
class Container {
constructor(list) {
this.list = list
}
getGetIterator() {
return new Iterator(this)
}
}
const arr = [100, 99, 3]
const list = new Container(arr)
const generate = list.getGetIterator()
console.log(generate.next())
console.log(generate.next())
console.log(generate.next())
console.log(generate.next())
使用场景
jQuery each
ES6 Iterator
有序数据集合都有 [Symbol.iterator]
属性
属性值是函数,执行函数返回一个迭代器,迭代器有next方法顺序返回子元素
可运行 Array.prototype [Symbol.iterator]
来测试
查看代码
js
const arr = [100, 99, 3]
// ES6 iterator
const iterator = arr[Symbol.iterator]()
// 有数据返回 {value: 100, done: false}
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// 没有数据返回 {value: undefined, done: true}
console.log(iterator.next())
// for of 语法
function each(data) {
// iterator 实现
const iterator = data[Symbol.iterator]()
let item = { done: false }
while (!item.done) {
item = iterator.next()
if (!item.done) {
console.log(item.value)
}
}
// for of 实现【带有遍历器特性的对象 Symbol.iterator有值】
for (const item of data) {
console.log(item)
}
}
each(arr)
const arr = [100, 99, 3]
// ES6 iterator
const iterator = arr[Symbol.iterator]()
// 有数据返回 {value: 100, done: false}
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// 没有数据返回 {value: undefined, done: true}
console.log(iterator.next())
// for of 语法
function each(data) {
// iterator 实现
const iterator = data[Symbol.iterator]()
let item = { done: false }
while (!item.done) {
item = iterator.next()
if (!item.done) {
console.log(item.value)
}
}
// for of 实现【带有遍历器特性的对象 Symbol.iterator有值】
for (const item of data) {
console.log(item)
}
}
each(arr)
3、状态模式
- 一个对象有状态变化
- 每次状态变化都会触发一个逻辑
- 不能总是用if...else来控制
示例
查看代码
js
// 状态模式
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
}
}
// 测试代码
let context = new Context()
let green = new State('green')
let yellow = new State('yellow')
let red = new State('red')
green.handle(context)
yellow.handle(context)
red.handle(context)
// 状态模式
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
}
}
// 测试代码
let context = new Context()
let green = new State('green')
let yellow = new State('yellow')
let red = new State('red')
green.handle(context)
yellow.handle(context)
red.handle(context)
场景
- 有限状态机
查看代码
js
import StateMachine from 'javascript-state-machine'
import $ from 'jquery'
// 初始化状态模型
let fsm = new StateMachine({
init: '收藏',
transitions: [
{
name: 'doStore',
from: '收藏',
to: '取消收藏'
},
{
name: 'deleteStore',
from: '取消收藏',
to: '收藏'
}
],
methods: {
// 监听执行收藏
onDoStore: function() {
alert('收藏成功')
updateText()
},
// 监听取消收藏
onDeleteStore: function() {
alert('已经取消收藏')
updateText()
}
}
})
let $btn = $('#btn1')
$btn.click(function() {
if (fsm.is('收藏')) {
fsm.doStore()
} else {
fsm.deleteStore()
}
})
// 更新按钮文案
function updateText() {
$btn.text(fsm.state)
}
// 初始化文案
updateText()
import StateMachine from 'javascript-state-machine'
import $ from 'jquery'
// 初始化状态模型
let fsm = new StateMachine({
init: '收藏',
transitions: [
{
name: 'doStore',
from: '收藏',
to: '取消收藏'
},
{
name: 'deleteStore',
from: '取消收藏',
to: '收藏'
}
],
methods: {
// 监听执行收藏
onDoStore: function() {
alert('收藏成功')
updateText()
},
// 监听取消收藏
onDeleteStore: function() {
alert('已经取消收藏')
updateText()
}
}
})
let $btn = $('#btn1')
$btn.click(function() {
if (fsm.is('收藏')) {
fsm.doStore()
} else {
fsm.deleteStore()
}
})
// 更新按钮文案
function updateText() {
$btn.text(fsm.state)
}
// 初始化文案
updateText()
- 写一个简单的promise
查看代码
js
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: {
// 监听执行收藏
onResolve: function(state, data) {
// state 当前状态机实例, data fsm.resolve(xxx) 传递的参数
data.successList.forEach(fn => fn())
},
// 监听取消收藏
onReject: function(state, data) {
data.failList.forEach(fn => fn())
}
}
})
class MyPromise {
constructor(fn) {
this.successList = []
this.failList = []
fn(
function() {
fsm.resolve(this)
},
function() {
fsm.reject(this)
}
)
}
then(successFn, failFn) {
this.successList.push(successFn)
this.failList.push(failFn)
}
}
const src = 'https://forguo.cn/favicon.ico'
const loadImg = src => {
const promise = new MyPromise(function(resolve, reject) {
const img = document.createElement('img')
img.onload = function() {
resolve(img)
}
img.onerror = function() {
reject()
}
img.src = src
})
return promise
}
const result = loadImg(src)
result.then(
function() {
console.log('ok1')
},
function() {
console.log('fail1')
}
)
result.then(
function() {
console.log('ok2')
},
function() {
console.log('fail2')
}
)
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: {
// 监听执行收藏
onResolve: function(state, data) {
// state 当前状态机实例, data fsm.resolve(xxx) 传递的参数
data.successList.forEach(fn => fn())
},
// 监听取消收藏
onReject: function(state, data) {
data.failList.forEach(fn => fn())
}
}
})
class MyPromise {
constructor(fn) {
this.successList = []
this.failList = []
fn(
function() {
fsm.resolve(this)
},
function() {
fsm.reject(this)
}
)
}
then(successFn, failFn) {
this.successList.push(successFn)
this.failList.push(failFn)
}
}
const src = 'https://forguo.cn/favicon.ico'
const loadImg = src => {
const promise = new MyPromise(function(resolve, reject) {
const img = document.createElement('img')
img.onload = function() {
resolve(img)
}
img.onerror = function() {
reject()
}
img.src = src
})
return promise
}
const result = loadImg(src)
result.then(
function() {
console.log('ok1')
},
function() {
console.log('fail1')
}
)
result.then(
function() {
console.log('ok2')
},
function() {
console.log('fail2')
}
)
4、策略模式
- 不同策略分开处理
- 避免出现大量if...else或者switch...case
5、模板方法模式
- 一步操作可能分为多个职责角色来完成
- 把这些角色都分开,然后再用一个统一的方法来调用,这个统一的方法就是模板方法
- 将发起者和各个职责角色解耦
6、职责连模式
介绍
- jQuery链式操作,Promise.then 的链式操作
7、命令模式
- 执行命令时,发布者和执行者分开
- 中间加入命令对象,作为中转站
- JS中的Promise
8、备忘录模式
- 随时记录一个对象的状态变化
- 随时可以恢复之前的某个状态(如撤销功能)
查看代码
js
// 备忘录模式
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
}
saveContentToMemento() {
return new Memento(this.content)
}
getContentFromMemento(memento) {
this.content = memento.getContent()
}
}
// 测试代码
let editor = new Editor()
let careTaker = new CareTaker()
editor.setContent('111')
editor.setContent('222')
careTaker.add(editor.saveContentToMemento()) // 保存备忘录
editor.setContent('333')
careTaker.add(editor.saveContentToMemento()) // 保存备忘录
editor.setContent('444')
console.log(editor.getContent()) // 444
editor.getContentFromMemento(careTaker.get(1)) // 撤销
console.log(editor.getContent()) // 333
editor.getContentFromMemento(careTaker.get(0)) // 撤销
console.log(editor.getContent()) // 111
// 备忘录模式
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
}
saveContentToMemento() {
return new Memento(this.content)
}
getContentFromMemento(memento) {
this.content = memento.getContent()
}
}
// 测试代码
let editor = new Editor()
let careTaker = new CareTaker()
editor.setContent('111')
editor.setContent('222')
careTaker.add(editor.saveContentToMemento()) // 保存备忘录
editor.setContent('333')
careTaker.add(editor.saveContentToMemento()) // 保存备忘录
editor.setContent('444')
console.log(editor.getContent()) // 444
editor.getContentFromMemento(careTaker.get(1)) // 撤销
console.log(editor.getContent()) // 333
editor.getContentFromMemento(careTaker.get(0)) // 撤销
console.log(editor.getContent()) // 111
9、中介者模式
- 一个对象不可能与其他所有对象发生紧耦合关系,这样对象之间的网会非常复杂
- 中介者模式将网状结构分离为星型结构
10、访问者模式
- 将数据操作和数据结构进行分离
- JS中使用较少
11、解释器模式
- 描述语言语法如何定义,如何解释和编译
- 用于专业场景