Skip to content

结构型模式

Adapter(适配器)

意图

将一个类的接口转换为用户希望的另外一个接口。

常用场景:封装有缺陷的接口设计、统一多个类的接口设计、兼容老版本接口、适配不同格式的数据等。

javascript
// 目标接口
const target = {
  fn1() { },
  fn2() { },
  fn3() { },
}

// 需要适配的接口
const adaptee = {
  fn1() { },
  fnb() { },
  fnc() { }
}

// 完成 fn2, fn3。实现后的 adeptor 具备 target 相关接口
const adeptor = {
  ...adaptee,
  fn2() {
    adaptee.fnb()
  },
  fn3() {
    adaptee.fnc()
  }
}
// 目标接口
const target = {
  fn1() { },
  fn2() { },
  fn3() { },
}

// 需要适配的接口
const adaptee = {
  fn1() { },
  fnb() { },
  fnc() { }
}

// 完成 fn2, fn3。实现后的 adeptor 具备 target 相关接口
const adeptor = {
  ...adaptee,
  fn2() {
    adaptee.fnb()
  },
  fn3() {
    adaptee.fnc()
  }
}

Bridge(桥接)

意图

将抽象部分与它的实现部分分离,使它们可以独立地变化。

核心思想:将一些通用方法提取出来,维护一个Implementor类,该类定义更细颗粒度的操作方法,而Abstraction则是基于这些操作方法的较高层次的操作。

Abstraction

定义抽象类的接口,维护一个指向Implementor的指针

javascript
class Window {
  constructor() { }
  drawText() {}
  drawRect() {}
}
class Window {
  constructor() { }
  drawText() {}
  drawRect() {}
}

RefinedAbstraction

扩充由Abstraction定义的接口

javascript
class IconWindow extends Window {
  drawBorder() {
    this.drawText()
    this.drawRect()
  }
}
class IconWindow extends Window {
  drawBorder() {
    this.drawText()
    this.drawRect()
  }
}

Implementor

定义实现的类的接口,该接口不一定要与Abstraction接口完全一致。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作对的较高层次的操作。

javascript
class WindowImp {
  drawLine() { }
}
class WindowImp {
  drawLine() { }
}

ConcreteImplementor

实现Implementor接口

javascript
class XWindowImp extends WindowImp {
  drawLine() {
    // 画 window 上的线条
  }
}

class MacWindowImp extends WindowImp {
  drawLine() {
    // 画 Mac 上的线条
  }
}
class XWindowImp extends WindowImp {
  drawLine() {
    // 画 window 上的线条
  }
}

class MacWindowImp extends WindowImp {
  drawLine() {
    // 画 Mac 上的线条
  }
}

Composite(组合)

意图

将对象组合成树形接口以表示“部分 - 整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

如创建节点时,分为很多种情况。遇到数组时(Composite),又会递归去创建节点。

javascript
function createElement(node) {
  if (Array.isArray(node)) {
    node.forEach((child) => {
      createElement(child)
    })
  } else if (node.type === 'text') {
    createText()
  } else {
    createNode()
  }

}
function createElement(node) {
  if (Array.isArray(node)) {
    node.forEach((child) => {
      createElement(child)
    })
  } else if (node.type === 'text') {
    createText()
  } else {
    createNode()
  }

}

Decorator(装饰)

意图

动态地给一个对象添加一些额外职责。就增加功能来讲,Decorator模式相比于生成子类更加灵活。

javascript
function border(fn) {
  console.log('add border')
  return (...args) => {
    fn(...args)
  }
}

function shape(color) {
  console.log('shape:', color)
}

border(shape)('red')
function border(fn) {
  console.log('add border')
  return (...args) => {
    fn(...args)
  }
}

function shape(color) {
  console.log('shape:', color)
}

border(shape)('red')

Facade(外观)

意图

为子系统中的一组接口提供一个一致的界面,Facade 定义了一个高层接口,这个接口使得这一系统更容易使用

侧重于通过颗粒比较小的接口合成一个高层的接口,使得外部更容易调用。

javascript
const systemA = {
  fn1() { },
  fn2() { },
  fn3() { }
}

const systemB = {
  fn1() { },
  fn2() { },
  fn3() { }
}

// 高层接口
const facadeMethod = () => {
  systemA.fn1()
  systemB.fn2()
  systemB.fn3()
  systemA.fn3()
}
const systemA = {
  fn1() { },
  fn2() { },
  fn3() { }
}

const systemB = {
  fn1() { },
  fn2() { },
  fn3() { }
}

// 高层接口
const facadeMethod = () => {
  systemA.fn1()
  systemB.fn2()
  systemB.fn3()
  systemA.fn3()
}

Flyweight(享元)

意图

运用共享技术有效地支持大量细粒度的对象。

进行划分细颗粒度的对象,使得这些对象能够共享,达到减少内存占用的目的。

Proxy(代理)

意图

为其他对象提供一种代理以控制这个对象的访问。

javascript
const user = {
  name: '模式'
}

const validate = () => {
  console.log('校验 user')
}

const proxyUser = new Proxy(user, {
  get(target, propKey) {
    validate()
    return `代理_${target[propKey]}`
  }
})

console.log('proxyUser.name ==> ', proxyUser.name);
// 校验 user
// proxyUser.name ==> 代理_模式
const user = {
  name: '模式'
}

const validate = () => {
  console.log('校验 user')
}

const proxyUser = new Proxy(user, {
  get(target, propKey) {
    validate()
    return `代理_${target[propKey]}`
  }
})

console.log('proxyUser.name ==> ', proxyUser.name);
// 校验 user
// proxyUser.name ==> 代理_模式