JS设计模式

发布时间 2023-08-04 10:35:22作者: lix_uan

创建型设计模式

单例模式

class Person {
  constructor(name, age) {
    if (!Person.instance) {
      this.name = name
      this.age = age
      Person.instance = this
    }
    return Person.instance
  }
}

const p1 = new Person('张三', 18)
const p2 = new Person('李四', 20)

// Person { name: '张三', age: 18 } Person { name: '张三', age: 18 }
console.log(p1, p2)

原型模式

// 通过Object.create克隆一个一模一样的新对象
class Person {
  constructor(name) {
    this.name = name
  }
  say() {
    return `I am ${this.name}`
  }
}
const p = new Person('大p')
const p1 = Object.create(new Person())

// Person { name: '大p' } Person { name: '小p', age: 18 } I am 小p
p1.name = '小p'
p1.age = 18
console.log(p, p1, p1.say())

简单工厂模式

class Iphone {
  showname() {
    return 'i am iphone'
  }
}
class Huawei {
  showname() {
    return 'i am huawei'
  }
}

class PhoneFactory {
  static createPhone(type) {
    switch (type) {
      case 'iphone':
        return new iphone()
      case 'huawei':
        return new huawei()
      default:
        throw new Error('no this type')
    }
  }
}

// i am iphone   i am huawei
const iphone1 = PhoneFactory.createPhone('Iphone')
const huawei1 = PhoneFactory.createPhone('Huawei')
console.log(iphone1.showname(), ' ', huawei1.showname())

工厂方法模式

class Factory {
  constructor(phone) {
    if (this instanceof Factory && this[phone]) {
      return new this[phone]()
    } else {
      return console.log(`没有${phone}这个手机`)
    }
  }
}

Factory.prototype.ipone = class {
  showname() {
    return 'i am iphone'
  }
}

// i am iphone
const iphone = new Factory('ipone')
console.log(iphone.showname())

策略模式

// 避免过多的if...else
// function validator(value) {
//   if (!/\d+/.test(value)) {
//   console.log("请输入数字");
//   } else if (value === || !value) (
//   console.log("不可为空"");
//   // else if...

const myRule = {
  isNumber: val => typeof val === 'number',
  notNull: val => val !== '' && val !== null
}

const validator = (value, rules) => rules.every(rule => myRule[rule](value))

// false
console.log(validator('111', ['notNull', 'isNumber']))

建造者模式

// 使用建造者模式构建复杂对象
// 产品(Product)
class Car {
  constructor() {
    this.parts = []
  }

  addPart(part) {
    this.parts.push(part)
  }

  showInfo() {
    return this.parts.join(',')
  }
}

// 建造者(Builder)
class CarBuilder {
  constructor() {
    this.car = new Car()
  }

  addFrame() {
    this.car.addPart('frame')
    return this
  }

  addEngine() {
    this.car.addPart('engine')
    return this
  }

  addWheel() {
    this.car.addPart('wheel')
    return this
  }

  getCar() {
    return this.car
  }
}

// 指挥者(Director)
class Director {
  constructor(builder) {
    this.builder = builder
  }

  build() {
    return this.builder.addFrame().addEngine().addWheel().getCar()
  }
}

const car = new Director(new CarBuilder()).build()

// frame,engine,wheel
console.log(car.showInfo())

结构型设计模式

桥接模式

class Toast {
  constructor(ani) {
    this.ani = ani
  }

  show() {
    this.ani.show()
  }

  hide() {
    this.ani.hide()
  }
}

class Message {
  constructor(ani) {
    this.ani = ani
  }

  show() {
    this.ani.show()
  }

  hide() {
    this.ani.hide()
  }
}

const animation = {
  bounce: {
    show() {
      console.log('bounce show')
    },
    hide() {
      console.log('bounce hide')
    }
  },
  side: {
    show() {
      console.log('side show')
    },
    hide() {
      console.log('side hide')
    }
  }
}

const toast1 = new Toast(animation.side)
const message1 = new Message(animation.bounce)
toast1.show()
toast1.hide()
message1.show()
message1.hide()

外观模式

const drawCircle = () => console.log('drawCircle')
const drawRect = () => console.log('drawRect')
const drawTriangle = () => console.log('drawTriangle')

class ShapeMaker {
  constructor() {
    this.drawCircle = drawCircle
    this.drawRect = drawRect
    this.drawTriangle = drawTriangle
  }
}

const maker = new ShapeMaker()
maker.drawCircle()
maker.drawRect()
maker.drawTriangle()

享元模式

// 享元
class Icon {
  constructor(type) {
    this.type = type
  }
  draw(x, y) {
    console.log(`绘制${this.type}图标,坐标为(${x}, ${y})`)
  }
}

// 享元工厂
class IconFactory {
  constructor() {
    this.icons = {}
  }
  createIcon(type) {
    if (!this.icons[type]) {
      this.icons[type] = new Icon(type)
    }
    return this.icons[type]
  }
  getIconCount() {
    return Object.keys(this.icons).length
  }
}

// 绘制多个图标
const iconFactory = new IconFactory()
iconFactory.createIcon('heart').draw(10, 10)
iconFactory.createIcon('star').draw(20, 20)
iconFactory.createIcon('heart').draw(30, 30)
iconFactory.createIcon('star').draw(40, 40)
console.log(iconFactory.getIconCount())

适配器模式

const sqare = x => x * x

// 适配器, 以适配sqare方法
const sqareString = x => {
  const num = parseInt(x)
  return sqare(num)
}

console.log(sqareString('16'))

组合模式

// 允许将对象组合成树形结构
// 以统一的方式处理单个对象和对象的组合

class Component {
  constructor(name) {
    this.name = name
    this.children = []
  }

  addChildren(component) {
    this.children.push(component)
  }
}

const processTree = component => {
  console.log(component.name)
  component.children.forEach(child => {
    processTree(child)
  })
}

const root = new Component('root')
const child1 = new Component('child1')
const child2 = new Component('child2')
const child3 = new Component('child3')
root.addChildren(child1)
root.addChildren(child2)
child2.addChildren(child3)

processTree(root)

装饰模式

// 在不改变对象结构的情况下,动态的为对象添加额外功能
const op = x => x * 2

const decorate = fn => {
  return x => {
    const res = fn(x)
    return res + 10
  }
}
const fn = decorate(op)

console.log(fn(5)) // 20

发布订阅模式

const eventBus = {
  topics: {},
  subscribe: function (topic, listener) {
    if (!this.topics[topic]) {
      this.topics[topic] = []
    }
    this.topics[topic].push(listener)
  },
  publish: function (topic, data) {
    if (this.topics[topic]) {
      this.topics[topic].forEach(listener => {
        listener(data)
      })
    }
  }
}

const subscribe1 = eventBus.subscribe('topic1', data => {
  console.log('subscribe1', data)
})

const subscribe2 = eventBus.subscribe('topic2', data => {
  console.log('subscribe2', data)
})

eventBus.publish('topic1', 'hello topic1')
eventBus.publish('topic2', 'hello topic2')

迭代器设计模式

// 将遍历操作抽离出来
const eachFn = (arr, fn) => {
  for (let i = 0; i < arr.length; i++) {
    fn(arr[i])
  }
}

let sum = 0
let count = 0
eachFn([1, 2, 3, 4, 5], item => {
  sum += item
  count++
})

console.log(sum)
console.log(count)

模板方法模式

// 将公共部分抽取到父类

class BasicInfo {
  setSize() {}
  setColor() {}
  showInfo() {
    this.setSize()
    this.setColor()
  }
}

class Phone extends BasicInfo {
  constructor() {
    super()
    this.size = 5
    this.color = 'red'
  }

  setSize() {
    console.log(`size: ${this.size}`)
  }

  setColor() {
    console.log(`color: ${this.color}`)
  }
}

const phone = new Phone()
phone.showInfo()

状态模式

// 将不同的状态封装成独立的类
// 并定义一个公共接口来统一他们的行为

class LightState {
  constructor(light) {
    this.light = light
  }

  pressSwitch() {
    throw new Error('子类需要重写pressSwitch方法')
  }
}

class OnLightState extends LightState {
  constructor(light) {
    super(light)
  }

  pressSwitch() {
    console.log('关灯')
    this.light.setState(this.light.offLightState)
  }
}

class OffLightState extends LightState {
  constructor(light) {
    super(light)
  }

  pressSwitch() {
    console.log('开灯')
    this.light.setState(this.light.onLightState)
  }
}

class Light {
  constructor() {
    this.onLightState = new OnLightState(this)
    this.offLightState = new OffLightState(this)
    this.currentState = this.offLightState
  }

  setState(state) {
    this.currentState = state
  }

  pressSwitch() {
    this.currentState.pressSwitch()
  }
}

const light = new Light()
light.pressSwitch()
light.pressSwitch()
light.pressSwitch()

命令模式

// 将请求或操作封装成独立的对象,降低耦合度
class Light {
  on() {
    console.log('light on')
  }
  off() {
    console.log('light off')
  }
}

const lightOnCommand = light => {
  return () => light.on()
}

const lightOffCommand = light => {
  return () => light.off()
}

class RemoteControl {
  constructor(command) {
    this.command = command
  }

  execute() {
    this.command()
  }
}

const light = new Light()
const lightOn = lightOnCommand(light)
const lightOff = lightOffCommand(light)
const remoteControl = new RemoteControl()

remoteControl.command = lightOn
remoteControl.execute()
remoteControl.command = lightOff
remoteControl.execute()