Skip to content

创建型与结构型模式 ​

单例模式 ​

js
// 前端最常见的单例:Vuex Store
class Store {
  constructor() {
    if (Store.instance) return Store.instance
    this.state = {}
    Store.instance = this
  }
}
// 使用:const store = new Store() // 全局唯一

// 弹窗管理器
class ModalManager {
  static #instance

  constructor() {
    if (ModalManager.#instance) return ModalManager.#instance
    this.modals = new Map()
    ModalManager.#instance = this
  }

  show(name, config) { /* ... */ }
  hide(name) { /* ... */ }
}

// 模块化方式(推荐)
// store.js
export const store = {
  state: new Map(),
  set(key, val) { this.state.set(key, val) },
  get(key) { return this.state.get(key) },
}
// 前端最常见的单例:Vuex Store
class Store {
  constructor() {
    if (Store.instance) return Store.instance
    this.state = {}
    Store.instance = this
  }
}
// 使用:const store = new Store() // 全局唯一

// 弹窗管理器
class ModalManager {
  static #instance

  constructor() {
    if (ModalManager.#instance) return ModalManager.#instance
    this.modals = new Map()
    ModalManager.#instance = this
  }

  show(name, config) { /* ... */ }
  hide(name) { /* ... */ }
}

// 模块化方式(推荐)
// store.js
export const store = {
  state: new Map(),
  set(key, val) { this.state.set(key, val) },
  get(key) { return this.state.get(key) },
}

工厂模式 ​

js
// 创建不同 UI 组件
class ButtonFactory {
  createButton(type) {
    switch (type) {
      case 'primary':
        return new PrimaryButton()
      case 'secondary':
        return new SecondaryButton()
      case 'danger':
        return new DangerButton()
      default:
        throw new Error('Unknown button type')
    }
  }
}

// React 中简单工厂
function createButton(config) {
  const { type, text, onClick } = config
  const baseClass = 'btn'

  switch (type) {
    case 'primary':
      return <button className={`${baseClass} btn-primary`} onClick={onClick}>{text}</button>
    case 'icon':
      return <button className={`${baseClass} btn-icon`} onClick={onClick}><Icon name={text} /></button>
    default:
      return <button className={baseClass} onClick={onClick}>{text}</button>
  }
}

// axios 实例工厂
function createApiClient(baseURL) {
  const instance = axios.create({ baseURL })

  instance.interceptors.request.use(config => {
    config.headers.Authorization = `Bearer ${getToken()}`
    return config
  })

  instance.interceptors.response.use(
    res => res.data,
    err => handleError(err)
  )

  return instance
}

export const api = createApiClient(import.meta.env.VITE_API_URL)
export const authApi = createApiClient(import.meta.env.VITE_AUTH_URL)
// 创建不同 UI 组件
class ButtonFactory {
  createButton(type) {
    switch (type) {
      case 'primary':
        return new PrimaryButton()
      case 'secondary':
        return new SecondaryButton()
      case 'danger':
        return new DangerButton()
      default:
        throw new Error('Unknown button type')
    }
  }
}

// React 中简单工厂
function createButton(config) {
  const { type, text, onClick } = config
  const baseClass = 'btn'

  switch (type) {
    case 'primary':
      return <button className={`${baseClass} btn-primary`} onClick={onClick}>{text}</button>
    case 'icon':
      return <button className={`${baseClass} btn-icon`} onClick={onClick}><Icon name={text} /></button>
    default:
      return <button className={baseClass} onClick={onClick}>{text}</button>
  }
}

// axios 实例工厂
function createApiClient(baseURL) {
  const instance = axios.create({ baseURL })

  instance.interceptors.request.use(config => {
    config.headers.Authorization = `Bearer ${getToken()}`
    return config
  })

  instance.interceptors.response.use(
    res => res.data,
    err => handleError(err)
  )

  return instance
}

export const api = createApiClient(import.meta.env.VITE_API_URL)
export const authApi = createApiClient(import.meta.env.VITE_AUTH_URL)

代理模式 ​

js
// Vue 3 响应式系统核心
const reactive = (obj) => {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key)  // 依赖收集
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      const oldValue = target[key]
      const result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        trigger(target, key)  // 触发更新
      }
      return result
    },
  })
}

// 图片懒加载
const lazyImage = new Proxy(Image, {
  construct(target, args) {
    const img = new target(...args)
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        img.src = img.dataset.src
        observer.disconnect()
      }
    })
    observer.observe(img)
    return img
  },
})
// Vue 3 响应式系统核心
const reactive = (obj) => {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key)  // 依赖收集
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      const oldValue = target[key]
      const result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        trigger(target, key)  // 触发更新
      }
      return result
    },
  })
}

// 图片懒加载
const lazyImage = new Proxy(Image, {
  construct(target, args) {
    const img = new target(...args)
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        img.src = img.dataset.src
        observer.disconnect()
      }
    })
    observer.observe(img)
    return img
  },
})

装饰器模式 ​

js
// 高阶组件 (HOC)
function withLogger(Component) {
  return function Enhanced(props) {
    useEffect(() => {
      console.log(`${Component.name} mounted`)
      return () => console.log(`${Component.name} unmounted`)
    }, [])

    return <Component {...props} />
  }
}

// TypeScript 装饰器
function log(target, key, descriptor) {
  const original = descriptor.value
  descriptor.value = function (...args) {
    console.log(`[${key}] called with`, args)
    const result = original.apply(this, args)
    console.log(`[${key}] returned`, result)
    return result
  }
  return descriptor
}

class Calculator {
  @log
  add(a, b) { return a + b }
}

// React Hooks 也是装饰器思想的体现
function useLoading(fn) {
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)

  const execute = async (...args) => {
    setLoading(true)
    setError(null)
    try {
      return await fn(...args)
    } catch (e) {
      setError(e)
    } finally {
      setLoading(false)
    }
  }

  return { execute, loading, error }
}
// 高阶组件 (HOC)
function withLogger(Component) {
  return function Enhanced(props) {
    useEffect(() => {
      console.log(`${Component.name} mounted`)
      return () => console.log(`${Component.name} unmounted`)
    }, [])

    return <Component {...props} />
  }
}

// TypeScript 装饰器
function log(target, key, descriptor) {
  const original = descriptor.value
  descriptor.value = function (...args) {
    console.log(`[${key}] called with`, args)
    const result = original.apply(this, args)
    console.log(`[${key}] returned`, result)
    return result
  }
  return descriptor
}

class Calculator {
  @log
  add(a, b) { return a + b }
}

// React Hooks 也是装饰器思想的体现
function useLoading(fn) {
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)

  const execute = async (...args) => {
    setLoading(true)
    setError(null)
    try {
      return await fn(...args)
    } catch (e) {
      setError(e)
    } finally {
      setLoading(false)
    }
  }

  return { execute, loading, error }
}

组合模式 ​

js
// 组件树天然就是组合模式
// 文件:TreeNode.jsx
function TreeNode({ node }) {
  return (
    <div>
      <span>{node.name}</span>
      {node.children && (
        <div style={{ paddingLeft: 20 }}>
          {node.children.map(child => (
            <TreeNode key={child.id} node={child} />
          ))}
        </div>
      )}
    </div>
  )
}
// 组件树天然就是组合模式
// 文件:TreeNode.jsx
function TreeNode({ node }) {
  return (
    <div>
      <span>{node.name}</span>
      {node.children && (
        <div style={{ paddingLeft: 20 }}>
          {node.children.map(child => (
            <TreeNode key={child.id} node={child} />
          ))}
        </div>
      )}
    </div>
  )
}

适配器模式 ​

js
// 数据格式适配
class OldApiAdapter {
  static adapt(user) {
    return {
      fullName: `${user.first_name} ${user.last_name}`,
      email: user.email_address,
      age: new Date().getFullYear() - new Date(user.birth_date).getFullYear(),
      avatar: user.profile_pic_url,
    }
  }
}

// 浏览器 API 适配
class StorageAdapter {
  constructor(type = 'local') {
    this.storage = type === 'local' ? localStorage : sessionStorage
  }

  get(key) {
    try {
      return JSON.parse(this.storage.getItem(key))
    } catch {
      return this.storage.getItem(key)
    }
  }

  set(key, value) {
    this.storage.setItem(key, JSON.stringify(value))
  }

  remove(key) {
    this.storage.removeItem(key)
  }
}
// 数据格式适配
class OldApiAdapter {
  static adapt(user) {
    return {
      fullName: `${user.first_name} ${user.last_name}`,
      email: user.email_address,
      age: new Date().getFullYear() - new Date(user.birth_date).getFullYear(),
      avatar: user.profile_pic_url,
    }
  }
}

// 浏览器 API 适配
class StorageAdapter {
  constructor(type = 'local') {
    this.storage = type === 'local' ? localStorage : sessionStorage
  }

  get(key) {
    try {
      return JSON.parse(this.storage.getItem(key))
    } catch {
      return this.storage.getItem(key)
    }
  }

  set(key, value) {
    this.storage.setItem(key, JSON.stringify(value))
  }

  remove(key) {
    this.storage.removeItem(key)
  }
}