JavaScript 设计模式----其他模式
-
- 1. 其他模式
-
-
- 1.1 创建型
-
- 1.2 结构型
-
-
- 1.2.1 桥接模式
- 1.2.2 组合模式
- 1.2.3 享元模式
- 1.2.4 外观模式
- 1.3 行为型
-
-
- 1.3.1 策略模式
- 1.3.2 模版方法模式
- 1.3.3 职责链模式
- 1.3.4 命令模式
- 1.3.5 备忘录模式
- 1.3.6 中介者模式
- 1.3.7 访问者模式
- 1.3.8 解释器模式
1. 其他模式
1.1 创建型
1.1.1 原型模式
概念
clone 自己,生成一个对象
java 默认有 clone 接口,不用自己实现
JS 中的应用 - Object.create
var prototype = {
getName: function () {
return this.first + ' ' + this.last
},
say: function () {
console.log('hello')
}
}
var x = Object.create(prototype)
x.first = 'A'
x.last = 'B'
console.log(x.getName())
x.say()
var y = Object.create(prototype)
y.first = 'C'
y.last = 'D'
console.log(y.getName())
y.say()
对比 JS 中的原型 prototype
prototype
可以理解为 ES6 class 的一种底层原理
- 而
class 是实现面向对象的基础
,并不是服务于某个模式
- 若干年后 ES6 全面普及,大家可能会忽略掉 prototype
- 但是 Object.create 却会长久存在
1.2 结构型
1.2.1 桥接模式
概念
演示
代码实现
class ColorShape {
yellowCircle() {
console.log('yellow circle')
}
redCircle() {
console.log('red circle')
}
yellowTriangle() {
console.log('yellow triangle')
}
redTriangle() {
console.log('red triangle')
}
}
let cs = new ColorShape()
cs.yellowCircle()
cs.redCircle()
cs.yellowTriangle()
cs.redTriangle()
演示
代码演示
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}`)
}
}
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()
1.2.2 组合模式
概念
生成树形结构,表示“整体-部分”关系
让整体和部分都具有一致的操作方式
示例
演示
- JS 经典应用中,未找到这么复杂的数据类型
虚拟 DOM 中的 vnode 是这种形式,但数据类型简单
- 用 JS 实现一个菜单,不算经典应用,与业务相关
<div id="div1" class="container">
<p>123p>
<p>456p>
div>
{
tag: 'div',
attr: {
id: 'div1',
className: 'container'
},
children: [
{
tag: 'p',
attr: {},
children: ['123']
},
{
tag: 'p',
attr: {},
children: ['456']
}
]
}
演示
整体和单个节点的操作是一致的
整体和单个节点的数据结构也保持一致
设计原则验证
1.2.3 享元模式
概念
共享内存(主要考虑内存,而非效率)
相同的数据,共享使用
演示
<div id="div1">
<a href="#">a1a>
<a href="#">a2a>
<a href="#">a3a>
<a href="#">a4a>
div>
<script>
var div1 = document.getElementById('div1')
div1.addEventListener('click', function(e) {
var target = e.target
if (e.nodeName === 'A') {
alert(target.innerHTML)
}
})
script>
1.2.4 外观模式
概念
为子系统中的一组接口提供了一个高层接口
使用者使用这个高层接口
示例
UML 类图
场景
function bindEvent(elem, type, selector, fn) {
if (fn == null) {
fn = selector
selector = null
}
}
bindEvent(elem, 'click', '#div1', fn)
bindEvent(elem, 'click', fn)
设计原则验证
不符合单一职责原则和开放封闭原则,因此谨慎使用,不可滥用
1.3 行为型
1.3.1 策略模式
概念
不同策略分开处理
避免出现大量 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 用户购买')
}
}
}
var u1 = new User('ordinary')
u1.buy()
var u2 = new User('member')
u2.buy()
var u3 = new User('vip')
u3.buy()
class OrdinaryUser {
buy() {
console.log('普通用户购买')
}
}
class MemberUser {
buy() {
console.log('会员用户购买')
}
}
class VipUser {
buy() {
console.log('vip 用户购买')
}
}
var u1 = new OrdinaryUser()
u1.buy()
var u2 = new MemberUser()
u2.buy()
var u3 = new VipUser()
u3.buy()
设计原则验证
不同策略,分开处理,而不是混合在一起
符合开放封闭原则
1.3.2 模版方法模式
class Action {
handle() {
handle1()
handle2()
handle3()
}
handle1() {
console.log('1')
}
handle2() {
console.log('2')
}
handle3() {
console.log('3')
}
}
1.3.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()
JS 中的链式操作
- 职责链模式和业务结合较多,JS 中能联想到
链式操作
jQuery 的链式操作 Promise.then 的链式操作
设计原则验证
1.3.4 命令模式
概念
执行命令时,发布者和执行者分开
中间加入命令对象,作为中转站
示例
演示
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 trumpeter = new Command(soldier)
let general = new Invoker(trumpeter)
general.invoke()
JS 中的应用
网页富文本编辑器操作,浏览器封装了一个命令对象
document.execCommand('bold')
document.execCommand('undo')
设计原则验证
1.3.5 备忘录模式
概念
随时记录一个对象的状态变化
随时可以恢复之前的某个状态(如撤销功能)
- 未找到 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 {
constuctor() {
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())
editor.getContentFromMemento(careTaker.get(1))
console.log(editor.getContent())
editor.getContentFromMemento(careTaker.get(0))
console.log(editor.getContent())
1.3.6 中介者模式
概念
演示
class Mediator {
constructor(a, b) {
this.a = a
this.b = b
}
setA() {
let number = this.b.number
this.a.setNumber(number * 100)
}
setB() {
let number = this.a.number
this.b.setNumber(number / 100)
}
}
class A {
constructor() {
this.number = 0
}
setNumber(num, m) {
this.number = num
if (m) {
m.setB()
}
}
}
class B {
constructor() {
this.number = 0
}
setNumber(num, m) {
this.number = num
if (m) {
m.setA()
}
}
}
let a = new A()
let b = new B()
let m = new Mediator(a, b)
a.setNumber(100)
console.log(a.number, b.number)
b.setNumber(100)
console.log(a.number, b.number)
1.3.7 访问者模式
1.3.8 解释器模式
概念
描述语言语法如何定义,如何解释和编译
用于专业场景