Javascript 设计模式系统讲解与应用——学习笔记11-其他设计模式

目录:

  • 创建型

    • 原型模式
  • 结构型

    • 桥接模式
    • 组合模式
    • 享元模式
  • 行为型

    • 策略模式
    • 模版方法模式 / 职责链模式
    • 命令模式
    • 备忘录模式
    • 中介者模式
    • 访问者模式
    • 解释器模式

创建型

原型模式

  • clone 自己,生成一个新对象
  • java默认有clone接口,不用自己实现

JS中的应用: Object.create

// Object.create 用到了原型模式的思想(虽然不是java中的clone)
// 基于一个原型创建一个对象
let prototype = {
  getName: function () {
    return this.first + ' ' + this.last
  },
  say: function () {
    console.log('hello')
  }
}

// 基于原型创建x
let x = Object.create(prototype)
x.first = 'A'
x.last = 'B'
console.log(x.getName())
x.say()

// 基于原型创建y
let y = Object.create(prototype)
y.first = 'C'
y.last = 'D'
console.log(y.getName())
y.say()

结构型

桥接模式

  • 用于把抽象化与实现化解耦
  • 使得二者可以独立变化

场景:
在一些业务中可能实现的比较多
在这里插入图片描述
设计原则验证:

  • 抽象和实现分离,解耦
  • 符合开放封闭原则

组合模式

  • 生成树形结构,表示“整体-部分”关系
  • 让整体和部分具有一致的操作方式
    在这里插入图片描述
    演示:
  • JS经典应用中,未找到这么复杂的数据类型
  • 虚拟DOM中的vnode是这种形式,但数据类型简单
  • 用JS实现一个菜单,不算经典应用,与业务相关
  • 整体和单个节点的操作是一致的
  • 整体和单个节点的数据结构也保持一致

设计原则验证

  • 将整体和单个节点的操作抽象出来
  • 符合开放封闭原则

享元模式

  • 共享内存(主要考虑内存,而非效率)
  • 相同的数据,共享使用
  • JS中未找到经典应用场景
    类似思想: 无限下拉列表,将事件代理到高层节点上,如果都绑定到<a>,对内存开销太大

设计原则验证

  • 将相同的部分抽象出来
  • 符合开放封闭原则

行为型

策略模式

  • 不同策略分开处理
  • 避免大量出现 if .. else 或者 switch ... case
  • JS中未找到经典应用场景

之前:

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用户购买')
    }
  }
}
// test
let u1 = new User('ordinary')
u1.buy()
let u2 = new User('member')
u2.buy()
let u3 = new User('vip')
u3.buy()

之后:

class OrdinaryUser {
  buy() {
    console.log('普通用户购买')
  }
}
class MemberUser{
  buy() {
    console.log('会员用户购买')
  }
}
class VipUser{
  buy() {
    console.log('会员用户购买')
  }
}

let u1 = new OrdinaryUser()
u1.buy()
let u2 = new MemberUser()
u2.buy()
let u3 = new VipUser()
u3.buy()

设计原则验证

  • 不同策略,分开处理,而不是混合在一起
  • 符合开放封闭原则

模版方法模式 / 职责链模式

  • 一步操作肯能分为多个职责角色来完成
  • 把这些角色放开,让后用一个链串起来
  • 将发起者和各个处理者进行隔离
// 请假审批,需要组长审批, 经理审批,最后总监审批
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 的链式操作

设计原则验证

  • 发起者于各个处理者进行隔离
  • 符合开放封闭原则

命令模式

  • 执行命令时,发布者和执行者分开
  • 中间加入命令对象,作为中转站
    在这里插入图片描述
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')

备忘录模式

  • 随时记录一个对象的状态变化
  • 随时可以恢复之前的某个状态(如撤销功能)
  • 未找到JS中经典应用,除了一些工具(如编辑器)
// 状态备忘
class Memennto {
  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()
  }
}

// test
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())  // 222

设计原则验证

  • 状态对象于使用者分开,解耦
  • 符合开放封闭原则

中介者模式

在这里插入图片描述

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) {
      a.setB()
    }
  }
}

class B {
  constructor() {
    this.number = 0
  }
  setNumber(num, m) {
    this.number = num
    if (m) {
      m.setA()
    }
  }
}

// test
let a = new A()
let b = new B()
let m = new Mediator(a, b)
a.setNumber(100, m)
console.log(a.number, b.number)
b.setNumber(100, m)
console.log(a.number, b.number)

设计原则验证

  • 将各关联对象通过中介者隔离
  • 符合开放封闭原则

访问者模式

  • 将数据操作和数据结构进行分离

解释器模式

  • 描述语言语法如何定义,如何解释和编译
  • 用于专业场景 (babel解释器…)
最后
  • 重点讲解的设计模式,要强制自己模仿,掌握
  • 非常用的设计模式,视业务场景选择性使用

版权声明:本文为weixin_40693643原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。