23种设计模式
- 创建型 工厂模式(工厂方法模式、抽象工厂模式、建造者模式)、单例模式、原型模式
- 组合型 适配器、装饰器、代理、外观、桥接、组合、享元
- 行为型 策略、模板方法、观察者、迭代器、职责链、命令、备忘录、状态、访问者、中介者、解释器
前面我们已经分别详细讲了前端的一些学用设计模式,但是不常用的设计模式我们要需要了解一下。下面就大概讲一下其它不常用设计模式。
一、原型模式
1、概念
clone自已,生成一个新对象。(java默认有clone接口,不用自己实现)
2、应用
JS中的的应用: Object.create会以某个对象为原型创建新对象。
// 基于一个原型创建一个对象
const prototype = {
getName: function () {
return this.first + ' ' + this.last
},
say: function () {
console.log('hello, I am ' + this.getName())
}
}
// 基于原型创建x
let x = Object.create(prototype)
x.first = 'A'
x.last = 'B'
x.say() // => hello, I am A B
// 基于原型创建x
let y = Object.create(prototype)
y.first = 'C'
y.last = 'D'
y.say() // => hello, I am C D
JS中的原型prototype
JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
原型prototype的代码示例如下:
function Animal(name) {
this.name = name;
}
Animal.prototype.color = 'white';
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color // 'white'
cat2.color // 'white'
JS中的面向对象就是基于prototype实现的。ES6中的class的底层原型其实就是prototype。
二、桥接模式
1、概念
用于把抽象化与实现化解耦,使得二者可以独立变化 。
2、示例讲解
只看概念有点不好理解,我们以一个示例为讲解。现在有一个需求,需要画不同形状不同颜色的图形。
第一种做法是: 每一个图形都单独使用一个方法画形状和颜色。复用性不高。
第二种做法是: 使用两个类(形状类、颜色类)把形状和颜色解耦。分别维护形状和颜色,复用性更高。
三、组合模式
1、概念
生成树形结构,表示“整体-部分”关系,让整体和部分都具有一致的数据结构和操作方式。
2、示例讲解
3、应用
- 虚拟DOM中的vnode是这种形式
- 业务逻辑中的多级菜单也是这种思想
四、享元模式
1、概念
享元两个字应该先分开解释。享是共享,元是元数据。
共享内存(主要考虑内存,而非效率)。相同的数据,共享使用。
2、示例演示
该示例适用于代理模式,也适用于享元模式。
五、责任链模式
1、概念
- 一步操作可能分为多个职责角色来完成;
- 把这些角色都分开,然后再用一个链串起来;
- 将发起者和各个处理者进行隔离;
2、示例
请假审批,需要组长审批、经理审批、最后总监审批
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()
3、JS中的链式操作
职责链模式和业务结合较多,JS中类似的能联想链式操作。 jQuery的链式操作、Promise.then的链式操作。
六、模板方法模式
1、概念
模板方法模式实际上封装了一个固定流程,该流程有几个步骤组成,具体步骤可以由子类进行不同的实现。
2、示例
七、命令模式
1、概念
执行命令时,发布者和执行者分开。中间加入命令对象作为中转站。
2、示例演示
有一个比较形象的例子是:将军发布命令,传令官传达命令,士兵执行。
// 接收者
class Receiver {
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()
}
}
// 士兵
let soldier = new Receiver()
// 传令官
let herald = new Command(soldier)
// 将军
let general = new Invoker(trumpeter)
general.invoke(()
3、JS中的应用
页面富文本编辑器操作,浏览器封装了一个命令对象
document.execCommand('bold') // 加粗
document.execCommand('undo') // 撤销
4、命令模式和发布订阅模式的区别
命令模式偏向于对一些琐碎 API 的封装,封装到一个命令对象,执行一个命令 API 。
八、备忘录模式
1、概念
- 随时记录一个对象的状态变化;
- 随时可经恢复之前的某人状态(如撤销功能);
// m1.js
// 备忘录类
class Memento {
constructor(content) {
this.content = content
}
getContent () {
return this.content
}
}
// 备忘录列表管理类
class CareTaker {
constructor() {
this.list = []
}
save (memento) {
this.list.push(memento)
}
restore (index) {
return this.list[index]
}
}
// 编辑器类
class Editor {
constructor() {
this.content = ''
this.careTaker = new CareTaker()
}
setContent (content) {
this.content = content
}
getContent () {
return this.content
}
save () {
this.careTaker.save(new Memento(this.content))
}
restore (index) {
const memento = this.careTaker.restore(index)
return memento && memento.getContent()
}
}
export default Editor
// index.js
import Editor from './m1'
const editor = new Editor()
editor.setContent('111')
editor.setContent('222')
editor.save()
editor.setContent('333')
editor.save()
editor.setContent('444')
console.log(editor.getContent()) // 444
console.log(editor.restore(2)) // undefined
console.log(editor.restore(1)) // 333
console.log(editor.restore(0)) // 222
九、中介者模式
1、概念
中介者模式是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。
意图: 用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
主要解决: 对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
2、代码演示
十、解释器模式
概念
- 描述语言语法如何定义,如何解释和编译
- 用于专业场景
十一、访问者模式
概念
将数据操作和数据结构进行分离。使用场景很少。