阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > JavaScript中设计模式的应用场景

JavaScript中设计模式的应用场景

作者:陈川 阅读数:9270人阅读 分类: JavaScript

JavaScript设计模式是解决特定问题的模板,它们提供了可复用的解决方案。理解这些模式的应用场景能提升代码的可维护性和扩展性。

单例模式的应用场景

单例模式确保一个类只有一个实例,并提供一个全局访问点。在JavaScript中,单例常用于管理全局状态或共享资源。

典型应用场景包括:

  1. 全局配置对象
  2. 缓存系统
  3. 日志系统
  4. 数据库连接池
class DatabaseConnection {
  constructor() {
    if (DatabaseConnection.instance) {
      return DatabaseConnection.instance
    }
    this.connection = this.createConnection()
    DatabaseConnection.instance = this
  }

  createConnection() {
    // 创建数据库连接逻辑
    return { status: 'connected' }
  }
}

const db1 = new DatabaseConnection()
const db2 = new DatabaseConnection()
console.log(db1 === db2) // true

观察者模式的应用场景

观察者模式定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知。这种模式特别适合实现事件处理系统。

常见应用场景:

  1. DOM事件监听
  2. 数据绑定系统
  3. 自定义事件系统
  4. 状态管理库(如Redux)
class EventEmitter {
  constructor() {
    this.events = {}
  }

  on(event, listener) {
    if (!this.events[event]) {
      this.events[event] = []
    }
    this.events[event].push(listener)
  }

  emit(event, ...args) {
    if (this.events[event]) {
      this.events[event].forEach(listener => listener(...args))
    }
  }
}

const emitter = new EventEmitter()
emitter.on('data', (data) => console.log('Received:', data))
emitter.emit('data', { id: 1, value: 'test' })

工厂模式的应用场景

工厂模式提供创建对象的接口,让子类决定实例化哪个类。在JavaScript中,工厂模式常用于创建复杂对象或需要统一创建逻辑的场景。

典型应用场景:

  1. UI组件库
  2. 跨平台对象创建
  3. 复杂对象构造
  4. 依赖解耦
class Button {
  render() {
    throw new Error('必须实现render方法')
  }
}

class WindowsButton extends Button {
  render() {
    return '<button style="padding: 8px 16px">Windows风格按钮</button>'
  }
}

class MacButton extends Button {
  render() {
    return '<button style="padding: 12px 24px; border-radius: 6px">Mac风格按钮</button>'
  }
}

function createButton(os) {
  switch (os) {
    case 'windows':
      return new WindowsButton()
    case 'mac':
      return new MacButton()
    default:
      throw new Error('不支持的操作系统')
  }
}

const winBtn = createButton('windows')
console.log(winBtn.render())

策略模式的应用场景

策略模式定义一系列算法,把它们封装起来,并且使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户。

常见应用场景:

  1. 表单验证规则
  2. 支付方式选择
  3. 排序算法切换
  4. 折扣计算策略
const strategies = {
  isNonEmpty(value, errorMsg) {
    if (value === '') {
      return errorMsg
    }
  },
  minLength(value, length, errorMsg) {
    if (value.length < length) {
      return errorMsg
    }
  },
  isMobile(value, errorMsg) {
    if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
      return errorMsg
    }
  }
}

class Validator {
  constructor() {
    this.cache = []
  }

  add(value, rule, errorMsg) {
    const ary = rule.split(':')
    this.cache.push(() => {
      const strategy = ary.shift()
      ary.unshift(value)
      ary.push(errorMsg)
      return strategies[strategy].apply(null, ary)
    })
  }

  validate() {
    for (let i = 0; i < this.cache.length; i++) {
      const msg = this.cache[i]()
      if (msg) {
        return msg
      }
    }
  }
}

const validator = new Validator()
validator.add('13812345678', 'isMobile', '手机号码格式不正确')
validator.add('', 'isNonEmpty', '密码不能为空')
const errorMsg = validator.validate()
console.log(errorMsg) // 密码不能为空

装饰者模式的应用场景

装饰者模式动态地给对象添加额外职责,相比继承更加灵活。在JavaScript中,装饰者模式常用于功能扩展。

典型应用场景:

  1. 高阶组件
  2. 中间件系统
  3. 功能增强
  4. AOP编程
function withLogging(WrappedComponent) {
  return class extends React.Component {
    componentDidMount() {
      console.log(`Component ${WrappedComponent.name} mounted`)
    }

    componentWillUnmount() {
      console.log(`Component ${WrappedComponent.name} will unmount`)
    }

    render() {
      return <WrappedComponent {...this.props} />
    }
  }
}

class MyComponent extends React.Component {
  render() {
    return <div>原始组件</div>
  }
}

const EnhancedComponent = withLogging(MyComponent)

适配器模式的应用场景

适配器模式将一个接口转换成客户希望的另一个接口,使接口不兼容的类可以一起工作。在JavaScript中,适配器常用于接口转换。

常见应用场景:

  1. 第三方库适配
  2. API版本兼容
  3. 数据格式转换
  4. 新旧系统对接
// 旧版API
class OldAPI {
  request() {
    return { data: 'old format', status: 200 }
  }
}

// 新版API需要的格式
class NewAPI {
  fetch() {
    return { result: 'new format', code: 200 }
  }
}

// 适配器
class APIAdapter {
  constructor(api) {
    this.api = api
  }

  fetch() {
    const result = this.api.request()
    return {
      result: result.data,
      code: result.status
    }
  }
}

const oldAPI = new OldAPI()
const adapter = new APIAdapter(oldAPI)
console.log(adapter.fetch()) // { result: 'old format', code: 200 }

代理模式的应用场景

代理模式为其他对象提供一种代理以控制对这个对象的访问。在JavaScript中,代理模式常用于访问控制、延迟初始化等。

典型应用场景:

  1. 图片懒加载
  2. 缓存代理
  3. 访问控制
  4. ES6 Proxy应用
class RealImage {
  constructor(filename) {
    this.filename = filename
    this.loadFromDisk()
  }

  loadFromDisk() {
    console.log(`Loading ${this.filename}`)
  }

  display() {
    console.log(`Displaying ${this.filename}`)
  }
}

class ProxyImage {
  constructor(filename) {
    this.filename = filename
    this.realImage = null
  }

  display() {
    if (!this.realImage) {
      this.realImage = new RealImage(this.filename)
    }
    this.realImage.display()
  }
}

const image = new ProxyImage('test.jpg')
// 图片尚未加载
image.display() // 此时才会真正加载

状态模式的应用场景

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。这种模式特别适合处理复杂的状态逻辑。

常见应用场景:

  1. 游戏角色状态
  2. 订单状态管理
  3. UI组件状态
  4. 工作流引擎
class TrafficLight {
  constructor() {
    this.states = [new RedLight(), new YellowLight(), new GreenLight()]
    this.current = this.states[0]
  }

  change() {
    const totalStates = this.states.length
    let currentIndex = this.states.findIndex(light => light === this.current)
    this.current = this.states[(currentIndex + 1) % totalStates]
  }

  sign() {
    return this.current.sign()
  }
}

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

class RedLight extends Light {
  constructor() {
    super('red')
  }

  sign() {
    return 'STOP'
  }
}

class YellowLight extends Light {
  constructor() {
    super('yellow')
  }

  sign() {
    return 'STEADY'
  }
}

class GreenLight extends Light {
  constructor() {
    super('green')
  }

  sign() {
    return 'GO'
  }
}

const trafficLight = new TrafficLight()
console.log(trafficLight.sign()) // STOP
trafficLight.change()
console.log(trafficLight.sign()) // STEADY
trafficLight.change()
console.log(trafficLight.sign()) // GO

命令模式的应用场景

命令模式将请求封装为对象,从而允许使用不同的请求、队列或日志来参数化其他对象。这种模式特别适合实现撤销/重做功能。

典型应用场景:

  1. 撤销/重做操作
  2. 宏命令
  3. 任务队列
  4. 事务系统
class Calculator {
  constructor() {
    this.current = 0
    this.history = []
  }

  execute(command) {
    this.current = command.execute(this.current)
    this.history.push(command)
  }

  undo() {
    const command = this.history.pop()
    this.current = command.undo(this.current)
  }

  getValue() {
    return this.current
  }
}

class AddCommand {
  constructor(value) {
    this.value = value
  }

  execute(current) {
    return current + this.value
  }

  undo(current) {
    return current - this.value
  }
}

class MultiplyCommand {
  constructor(value) {
    this.value = value
  }

  execute(current) {
    return current * this.value
  }

  undo(current) {
    return current / this.value
  }
}

const calculator = new Calculator()
calculator.execute(new AddCommand(10))
calculator.execute(new MultiplyCommand(2))
console.log(calculator.getValue()) // 20
calculator.undo()
console.log(calculator.getValue()) // 10

组合模式的应用场景

组合模式将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

常见应用场景:

  1. UI组件树
  2. 文件系统
  3. 组织结构图
  4. 菜单系统
class Component {
  constructor(name) {
    this.name = name
  }

  add(component) {
    throw new Error('不支持的操作')
  }

  remove(component) {
    throw new Error('不支持的操作')
  }

  display(depth) {
    throw new Error('必须实现display方法')
  }
}

class Leaf extends Component {
  constructor(name) {
    super(name)
  }

  display(depth) {
    console.log(`${'-'.repeat(depth)}${this.name}`)
  }
}

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

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

  remove(component) {
    const index = this.children.indexOf(component)
    if (index !== -1) {
      this.children.splice(index, 1)
    }
  }

  display(depth) {
    console.log(`${'-'.repeat(depth)}${this.name}`)
    this.children.forEach(child => child.display(depth + 2))
  }
}

const root = new Composite('root')
root.add(new Leaf('Leaf A'))
root.add(new Leaf('Leaf B'))

const comp = new Composite('Composite X')
comp.add(new Leaf('Leaf XA'))
comp.add(new Leaf('Leaf XB'))

root.add(comp)
root.display(1)

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌