发布于

JavaScript设计模式实战:从经典模式到现代应用架构

作者

JavaScript设计模式实战:从经典模式到现代应用架构

设计模式是解决常见编程问题的可复用解决方案。本文将深入探讨JavaScript中的经典设计模式和现代应用架构模式。

创建型模式

单例模式 (Singleton Pattern)

// 经典单例模式实现
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance
    }
    
    this.data = {}
    this.timestamp = Date.now()
    
    Singleton.instance = this
    return this
  }
  
  getData(key) {
    return this.data[key]
  }
  
  setData(key, value) {
    this.data[key] = value
  }
  
  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton()
    }
    return Singleton.instance
  }
}

// 使用示例
const instance1 = new Singleton()
const instance2 = new Singleton()
const instance3 = Singleton.getInstance()

console.log(instance1 === instance2) // true
console.log(instance2 === instance3) // true

// 现代化的单例模式 - 使用模块
const ConfigManager = (() => {
  let instance = null
  
  class Config {
    constructor() {
      this.settings = {
        apiUrl: 'https://api.example.com',
        timeout: 5000,
        retries: 3
      }
    }
    
    get(key) {
      return this.settings[key]
    }
    
    set(key, value) {
      this.settings[key] = value
    }
    
    update(newSettings) {
      this.settings = { ...this.settings, ...newSettings }
    }
  }
  
  return {
    getInstance() {
      if (!instance) {
        instance = new Config()
      }
      return instance
    }
  }
})()

// 应用配置管理器
const config = ConfigManager.getInstance()
config.set('theme', 'dark')
console.log(config.get('theme')) // 'dark'

// 数据库连接单例
class DatabaseConnection {
  constructor() {
    if (DatabaseConnection.instance) {
      return DatabaseConnection.instance
    }
    
    this.connection = null
    this.isConnected = false
    
    DatabaseConnection.instance = this
  }
  
  async connect(connectionString) {
    if (this.isConnected) {
      return this.connection
    }
    
    try {
      // 模拟数据库连接
      this.connection = await this.createConnection(connectionString)
      this.isConnected = true
      console.log('Database connected')
      return this.connection
    } catch (error) {
      console.error('Database connection failed:', error)
      throw error
    }
  }
  
  async createConnection(connectionString) {
    // 模拟异步连接过程
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve({ id: Math.random(), connectionString })
      }, 1000)
    })
  }
  
  async disconnect() {
    if (this.isConnected) {
      this.connection = null
      this.isConnected = false
      console.log('Database disconnected')
    }
  }
  
  getConnection() {
    if (!this.isConnected) {
      throw new Error('Database not connected')
    }
    return this.connection
  }
}

// 使用数据库连接单例
const db1 = new DatabaseConnection()
const db2 = new DatabaseConnection()
console.log(db1 === db2) // true

工厂模式 (Factory Pattern)

// 简单工厂模式
class ButtonFactory {
  static createButton(type, props = {}) {
    switch (type) {
      case 'primary':
        return new PrimaryButton(props)
      case 'secondary':
        return new SecondaryButton(props)
      case 'danger':
        return new DangerButton(props)
      default:
        throw new Error(`Unknown button type: ${type}`)
    }
  }
}

class Button {
  constructor(props) {
    this.text = props.text || 'Button'
    this.onClick = props.onClick || (() => {})
  }
  
  render() {
    const button = document.createElement('button')
    button.textContent = this.text
    button.addEventListener('click', this.onClick)
    return button
  }
}

class PrimaryButton extends Button {
  render() {
    const button = super.render()
    button.className = 'btn btn-primary'
    return button
  }
}

class SecondaryButton extends Button {
  render() {
    const button = super.render()
    button.className = 'btn btn-secondary'
    return button
  }
}

class DangerButton extends Button {
  render() {
    const button = super.render()
    button.className = 'btn btn-danger'
    return button
  }
}

// 使用工厂创建按钮
const primaryBtn = ButtonFactory.createButton('primary', {
  text: 'Save',
  onClick: () => console.log('Saving...')
})

const dangerBtn = ButtonFactory.createButton('danger', {
  text: 'Delete',
  onClick: () => console.log('Deleting...')
})

// 抽象工厂模式
class UIFactory {
  createButton() {
    throw new Error('createButton method must be implemented')
  }
  
  createInput() {
    throw new Error('createInput method must be implemented')
  }
}

class MaterialUIFactory extends UIFactory {
  createButton(props) {
    return new MaterialButton(props)
  }
  
  createInput(props) {
    return new MaterialInput(props)
  }
}

class BootstrapUIFactory extends UIFactory {
  createButton(props) {
    return new BootstrapButton(props)
  }
  
  createInput(props) {
    return new BootstrapInput(props)
  }
}

// UI组件基类
class UIComponent {
  constructor(props) {
    this.props = props
  }
}

class MaterialButton extends UIComponent {
  render() {
    const button = document.createElement('button')
    button.className = 'mdc-button mdc-button--raised'
    button.textContent = this.props.text
    return button
  }
}

class BootstrapButton extends UIComponent {
  render() {
    const button = document.createElement('button')
    button.className = 'btn btn-primary'
    button.textContent = this.props.text
    return button
  }
}

class MaterialInput extends UIComponent {
  render() {
    const input = document.createElement('input')
    input.className = 'mdc-text-field__input'
    input.placeholder = this.props.placeholder
    return input
  }
}

class BootstrapInput extends UIComponent {
  render() {
    const input = document.createElement('input')
    input.className = 'form-control'
    input.placeholder = this.props.placeholder
    return input
  }
}

// 使用抽象工厂
const uiTheme = 'material' // 或 'bootstrap'
const factory = uiTheme === 'material' 
  ? new MaterialUIFactory() 
  : new BootstrapUIFactory()

const button = factory.createButton({ text: 'Click me' })
const input = factory.createInput({ placeholder: 'Enter text' })

// HTTP客户端工厂
class HttpClientFactory {
  static createClient(type, config = {}) {
    switch (type) {
      case 'fetch':
        return new FetchClient(config)
      case 'xhr':
        return new XHRClient(config)
      case 'axios':
        return new AxiosClient(config)
      default:
        return new FetchClient(config)
    }
  }
}

class HttpClient {
  constructor(config) {
    this.baseURL = config.baseURL || ''
    this.timeout = config.timeout || 5000
    this.headers = config.headers || {}
  }
  
  async get(url) {
    throw new Error('get method must be implemented')
  }
  
  async post(url, data) {
    throw new Error('post method must be implemented')
  }
}

class FetchClient extends HttpClient {
  async get(url) {
    const response = await fetch(`${this.baseURL}${url}`, {
      headers: this.headers,
      signal: AbortSignal.timeout(this.timeout)
    })
    return response.json()
  }
  
  async post(url, data) {
    const response = await fetch(`${this.baseURL}${url}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...this.headers
      },
      body: JSON.stringify(data),
      signal: AbortSignal.timeout(this.timeout)
    })
    return response.json()
  }
}

class XHRClient extends HttpClient {
  async get(url) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest()
      xhr.open('GET', `${this.baseURL}${url}`)
      
      Object.entries(this.headers).forEach(([key, value]) => {
        xhr.setRequestHeader(key, value)
      })
      
      xhr.timeout = this.timeout
      xhr.onload = () => resolve(JSON.parse(xhr.responseText))
      xhr.onerror = () => reject(new Error('Request failed'))
      xhr.ontimeout = () => reject(new Error('Request timeout'))
      
      xhr.send()
    })
  }
  
  async post(url, data) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest()
      xhr.open('POST', `${this.baseURL}${url}`)
      
      xhr.setRequestHeader('Content-Type', 'application/json')
      Object.entries(this.headers).forEach(([key, value]) => {
        xhr.setRequestHeader(key, value)
      })
      
      xhr.timeout = this.timeout
      xhr.onload = () => resolve(JSON.parse(xhr.responseText))
      xhr.onerror = () => reject(new Error('Request failed'))
      xhr.ontimeout = () => reject(new Error('Request timeout'))
      
      xhr.send(JSON.stringify(data))
    })
  }
}

// 使用HTTP客户端工厂
const httpClient = HttpClientFactory.createClient('fetch', {
  baseURL: 'https://api.example.com',
  timeout: 10000,
  headers: {
    'Authorization': 'Bearer token123'
  }
})

// 使用客户端
httpClient.get('/users').then(users => console.log(users))

建造者模式 (Builder Pattern)

// 查询构建器
class QueryBuilder {
  constructor() {
    this.query = {
      select: [],
      from: '',
      where: [],
      orderBy: [],
      limit: null,
      offset: null
    }
  }
  
  select(fields) {
    if (Array.isArray(fields)) {
      this.query.select.push(...fields)
    } else {
      this.query.select.push(fields)
    }
    return this
  }
  
  from(table) {
    this.query.from = table
    return this
  }
  
  where(condition) {
    this.query.where.push(condition)
    return this
  }
  
  orderBy(field, direction = 'ASC') {
    this.query.orderBy.push(`${field} ${direction}`)
    return this
  }
  
  limit(count) {
    this.query.limit = count
    return this
  }
  
  offset(count) {
    this.query.offset = count
    return this
  }
  
  build() {
    let sql = `SELECT ${this.query.select.join(', ')} FROM ${this.query.from}`
    
    if (this.query.where.length > 0) {
      sql += ` WHERE ${this.query.where.join(' AND ')}`
    }
    
    if (this.query.orderBy.length > 0) {
      sql += ` ORDER BY ${this.query.orderBy.join(', ')}`
    }
    
    if (this.query.limit) {
      sql += ` LIMIT ${this.query.limit}`
    }
    
    if (this.query.offset) {
      sql += ` OFFSET ${this.query.offset}`
    }
    
    return sql
  }
}

// 使用查询构建器
const query = new QueryBuilder()
  .select(['id', 'name', 'email'])
  .from('users')
  .where('age > 18')
  .where('status = "active"')
  .orderBy('created_at', 'DESC')
  .limit(10)
  .offset(20)
  .build()

console.log(query)
// SELECT id, name, email FROM users WHERE age > 18 AND status = "active" ORDER BY created_at DESC LIMIT 10 OFFSET 20

// HTTP请求构建器
class RequestBuilder {
  constructor() {
    this.config = {
      method: 'GET',
      url: '',
      headers: {},
      params: {},
      data: null,
      timeout: 5000
    }
  }
  
  method(method) {
    this.config.method = method.toUpperCase()
    return this
  }
  
  url(url) {
    this.config.url = url
    return this
  }
  
  header(key, value) {
    this.config.headers[key] = value
    return this
  }
  
  headers(headers) {
    Object.assign(this.config.headers, headers)
    return this
  }
  
  param(key, value) {
    this.config.params[key] = value
    return this
  }
  
  params(params) {
    Object.assign(this.config.params, params)
    return this
  }
  
  data(data) {
    this.config.data = data
    return this
  }
  
  timeout(timeout) {
    this.config.timeout = timeout
    return this
  }
  
  json(data) {
    this.config.data = JSON.stringify(data)
    this.config.headers['Content-Type'] = 'application/json'
    return this
  }
  
  auth(token) {
    this.config.headers['Authorization'] = `Bearer ${token}`
    return this
  }
  
  async send() {
    const url = new URL(this.config.url)
    
    // 添加查询参数
    Object.entries(this.config.params).forEach(([key, value]) => {
      url.searchParams.append(key, value)
    })
    
    const fetchConfig = {
      method: this.config.method,
      headers: this.config.headers,
      signal: AbortSignal.timeout(this.config.timeout)
    }
    
    if (this.config.data && this.config.method !== 'GET') {
      fetchConfig.body = this.config.data
    }
    
    const response = await fetch(url.toString(), fetchConfig)
    return response.json()
  }
}

// 使用请求构建器
const response = await new RequestBuilder()
  .method('POST')
  .url('https://api.example.com/users')
  .auth('your-token-here')
  .json({ name: 'John', email: 'john@example.com' })
  .timeout(10000)
  .send()

// 表单构建器
class FormBuilder {
  constructor() {
    this.form = document.createElement('form')
    this.fields = []
  }
  
  addField(type, name, options = {}) {
    const field = this.createField(type, name, options)
    this.fields.push(field)
    return this
  }
  
  createField(type, name, options) {
    const wrapper = document.createElement('div')
    wrapper.className = 'form-group'
    
    if (options.label) {
      const label = document.createElement('label')
      label.textContent = options.label
      label.setAttribute('for', name)
      wrapper.appendChild(label)
    }
    
    let input
    if (type === 'textarea') {
      input = document.createElement('textarea')
    } else if (type === 'select') {
      input = document.createElement('select')
      if (options.options) {
        options.options.forEach(opt => {
          const option = document.createElement('option')
          option.value = opt.value
          option.textContent = opt.text
          input.appendChild(option)
        })
      }
    } else {
      input = document.createElement('input')
      input.type = type
    }
    
    input.name = name
    input.id = name
    
    if (options.placeholder) {
      input.placeholder = options.placeholder
    }
    
    if (options.required) {
      input.required = true
    }
    
    if (options.value) {
      input.value = options.value
    }
    
    wrapper.appendChild(input)
    return wrapper
  }
  
  addSubmitButton(text = 'Submit') {
    const button = document.createElement('button')
    button.type = 'submit'
    button.textContent = text
    button.className = 'btn btn-primary'
    this.fields.push(button)
    return this
  }
  
  onSubmit(handler) {
    this.form.addEventListener('submit', handler)
    return this
  }
  
  build() {
    this.fields.forEach(field => {
      this.form.appendChild(field)
    })
    return this.form
  }
}

// 使用表单构建器
const form = new FormBuilder()
  .addField('text', 'name', { 
    label: 'Name', 
    placeholder: 'Enter your name',
    required: true 
  })
  .addField('email', 'email', { 
    label: 'Email', 
    placeholder: 'Enter your email',
    required: true 
  })
  .addField('select', 'country', {
    label: 'Country',
    options: [
      { value: 'us', text: 'United States' },
      { value: 'uk', text: 'United Kingdom' },
      { value: 'ca', text: 'Canada' }
    ]
  })
  .addField('textarea', 'message', {
    label: 'Message',
    placeholder: 'Enter your message'
  })
  .addSubmitButton('Send Message')
  .onSubmit((e) => {
    e.preventDefault()
    const formData = new FormData(e.target)
    console.log(Object.fromEntries(formData))
  })
  .build()

document.body.appendChild(form)

行为型模式

观察者模式 (Observer Pattern)

// 事件发射器实现
class EventEmitter {
  constructor() {
    this.events = new Map()
  }
  
  on(event, listener) {
    if (!this.events.has(event)) {
      this.events.set(event, [])
    }
    this.events.get(event).push(listener)
    
    // 返回取消订阅函数
    return () => this.off(event, listener)
  }
  
  once(event, listener) {
    const onceWrapper = (...args) => {
      listener(...args)
      this.off(event, onceWrapper)
    }
    return this.on(event, onceWrapper)
  }
  
  off(event, listener) {
    if (!this.events.has(event)) return
    
    const listeners = this.events.get(event)
    const index = listeners.indexOf(listener)
    
    if (index > -1) {
      listeners.splice(index, 1)
    }
    
    if (listeners.length === 0) {
      this.events.delete(event)
    }
  }
  
  emit(event, ...args) {
    if (!this.events.has(event)) return
    
    const listeners = this.events.get(event).slice() // 复制数组避免修改问题
    listeners.forEach(listener => {
      try {
        listener(...args)
      } catch (error) {
        console.error(`Error in event listener for "${event}":`, error)
      }
    })
  }
  
  removeAllListeners(event) {
    if (event) {
      this.events.delete(event)
    } else {
      this.events.clear()
    }
  }
  
  listenerCount(event) {
    return this.events.has(event) ? this.events.get(event).length : 0
  }
  
  eventNames() {
    return Array.from(this.events.keys())
  }
}

// 使用事件发射器
const emitter = new EventEmitter()

// 订阅事件
const unsubscribe = emitter.on('user:login', (user) => {
  console.log(`User ${user.name} logged in`)
})

emitter.on('user:logout', (user) => {
  console.log(`User ${user.name} logged out`)
})

// 一次性事件监听
emitter.once('app:ready', () => {
  console.log('Application is ready!')
})

// 发射事件
emitter.emit('user:login', { name: 'John', id: 1 })
emitter.emit('app:ready')
emitter.emit('app:ready') // 不会触发,因为是once

// 取消订阅
unsubscribe()

// 状态管理器使用观察者模式
class StateManager extends EventEmitter {
  constructor(initialState = {}) {
    super()
    this.state = { ...initialState }
    this.history = [this.state]
    this.currentIndex = 0
  }
  
  getState() {
    return { ...this.state }
  }
  
  setState(updates) {
    const prevState = { ...this.state }
    this.state = { ...this.state, ...updates }
    
    // 添加到历史记录
    this.history = this.history.slice(0, this.currentIndex + 1)
    this.history.push({ ...this.state })
    this.currentIndex = this.history.length - 1
    
    // 发射状态变化事件
    this.emit('stateChange', {
      prevState,
      nextState: { ...this.state },
      updates
    })
  }
  
  subscribe(listener) {
    return this.on('stateChange', listener)
  }
  
  undo() {
    if (this.currentIndex > 0) {
      this.currentIndex--
      this.state = { ...this.history[this.currentIndex] }
      this.emit('stateChange', {
        prevState: this.history[this.currentIndex + 1],
        nextState: { ...this.state },
        type: 'undo'
      })
    }
  }
  
  redo() {
    if (this.currentIndex < this.history.length - 1) {
      this.currentIndex++
      this.state = { ...this.history[this.currentIndex] }
      this.emit('stateChange', {
        prevState: this.history[this.currentIndex - 1],
        nextState: { ...this.state },
        type: 'redo'
      })
    }
  }
}

// 使用状态管理器
const store = new StateManager({ count: 0, user: null })

// 订阅状态变化
store.subscribe(({ prevState, nextState, updates }) => {
  console.log('State changed:', { prevState, nextState, updates })
})

// 更新状态
store.setState({ count: 1 })
store.setState({ user: { name: 'John' } })
store.setState({ count: 2 })

// 撤销/重做
store.undo() // count: 1
store.undo() // count: 0, user: null
store.redo() // count: 1

策略模式 (Strategy Pattern)

// 支付策略
class PaymentStrategy {
  pay(amount) {
    throw new Error('pay method must be implemented')
  }
}

class CreditCardPayment extends PaymentStrategy {
  constructor(cardNumber, cvv, expiryDate) {
    super()
    this.cardNumber = cardNumber
    this.cvv = cvv
    this.expiryDate = expiryDate
  }
  
  pay(amount) {
    console.log(`Paid $${amount} using Credit Card ending in ${this.cardNumber.slice(-4)}`)
    return {
      success: true,
      transactionId: `cc_${Date.now()}`,
      amount,
      method: 'credit_card'
    }
  }
}

class PayPalPayment extends PaymentStrategy {
  constructor(email) {
    super()
    this.email = email
  }
  
  pay(amount) {
    console.log(`Paid $${amount} using PayPal account ${this.email}`)
    return {
      success: true,
      transactionId: `pp_${Date.now()}`,
      amount,
      method: 'paypal'
    }
  }
}

class CryptoPayment extends PaymentStrategy {
  constructor(walletAddress, currency) {
    super()
    this.walletAddress = walletAddress
    this.currency = currency
  }
  
  pay(amount) {
    console.log(`Paid $${amount} using ${this.currency} from wallet ${this.walletAddress}`)
    return {
      success: true,
      transactionId: `crypto_${Date.now()}`,
      amount,
      method: 'cryptocurrency',
      currency: this.currency
    }
  }
}

// 支付处理器
class PaymentProcessor {
  constructor() {
    this.strategy = null
  }
  
  setStrategy(strategy) {
    this.strategy = strategy
  }
  
  processPayment(amount) {
    if (!this.strategy) {
      throw new Error('Payment strategy not set')
    }
    
    return this.strategy.pay(amount)
  }
}

// 使用支付策略
const processor = new PaymentProcessor()

// 信用卡支付
processor.setStrategy(new CreditCardPayment('1234567890123456', '123', '12/25'))
processor.processPayment(100)

// PayPal支付
processor.setStrategy(new PayPalPayment('user@example.com'))
processor.processPayment(50)

// 加密货币支付
processor.setStrategy(new CryptoPayment('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', 'BTC'))
processor.processPayment(0.001)

// 排序策略
class SortStrategy {
  sort(array) {
    throw new Error('sort method must be implemented')
  }
}

class BubbleSort extends SortStrategy {
  sort(array) {
    const arr = [...array]
    const n = arr.length
    
    for (let i = 0; i < n - 1; i++) {
      for (let j = 0; j < n - i - 1; j++) {
        if (arr[j] > arr[j + 1]) {
          [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
        }
      }
    }
    
    return arr
  }
}

class QuickSort extends SortStrategy {
  sort(array) {
    if (array.length <= 1) return array
    
    const pivot = array[Math.floor(array.length / 2)]
    const left = array.filter(x => x < pivot)
    const middle = array.filter(x => x === pivot)
    const right = array.filter(x => x > pivot)
    
    return [...this.sort(left), ...middle, ...this.sort(right)]
  }
}

class MergeSort extends SortStrategy {
  sort(array) {
    if (array.length <= 1) return array
    
    const middle = Math.floor(array.length / 2)
    const left = array.slice(0, middle)
    const right = array.slice(middle)
    
    return this.merge(this.sort(left), this.sort(right))
  }
  
  merge(left, right) {
    const result = []
    let leftIndex = 0
    let rightIndex = 0
    
    while (leftIndex < left.length && rightIndex < right.length) {
      if (left[leftIndex] < right[rightIndex]) {
        result.push(left[leftIndex])
        leftIndex++
      } else {
        result.push(right[rightIndex])
        rightIndex++
      }
    }
    
    return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex))
  }
}

// 排序器
class Sorter {
  constructor(strategy) {
    this.strategy = strategy
  }
  
  setStrategy(strategy) {
    this.strategy = strategy
  }
  
  sort(array) {
    console.time('Sort Time')
    const result = this.strategy.sort(array)
    console.timeEnd('Sort Time')
    return result
  }
}

// 使用排序策略
const data = [64, 34, 25, 12, 22, 11, 90]
const sorter = new Sorter(new QuickSort())

console.log('Original:', data)
console.log('Sorted:', sorter.sort(data))

// 切换策略
sorter.setStrategy(new MergeSort())
console.log('Merge sorted:', sorter.sort(data))

// 验证策略
class ValidationStrategy {
  validate(value) {
    throw new Error('validate method must be implemented')
  }
}

class EmailValidation extends ValidationStrategy {
  validate(email) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    return {
      isValid: emailRegex.test(email),
      message: emailRegex.test(email) ? 'Valid email' : 'Invalid email format'
    }
  }
}

class PasswordValidation extends ValidationStrategy {
  constructor(minLength = 8) {
    super()
    this.minLength = minLength
  }
  
  validate(password) {
    const hasMinLength = password.length >= this.minLength
    const hasUpperCase = /[A-Z]/.test(password)
    const hasLowerCase = /[a-z]/.test(password)
    const hasNumbers = /\d/.test(password)
    const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password)
    
    const isValid = hasMinLength && hasUpperCase && hasLowerCase && hasNumbers && hasSpecialChar
    
    const messages = []
    if (!hasMinLength) messages.push(`At least ${this.minLength} characters`)
    if (!hasUpperCase) messages.push('At least one uppercase letter')
    if (!hasLowerCase) messages.push('At least one lowercase letter')
    if (!hasNumbers) messages.push('At least one number')
    if (!hasSpecialChar) messages.push('At least one special character')
    
    return {
      isValid,
      message: isValid ? 'Valid password' : `Password must contain: ${messages.join(', ')}`
    }
  }
}

// 表单验证器
class FormValidator {
  constructor() {
    this.strategies = new Map()
  }
  
  addField(fieldName, strategy) {
    this.strategies.set(fieldName, strategy)
  }
  
  validate(formData) {
    const results = {}
    let isFormValid = true
    
    for (const [fieldName, strategy] of this.strategies) {
      const value = formData[fieldName]
      const result = strategy.validate(value)
      results[fieldName] = result
      
      if (!result.isValid) {
        isFormValid = false
      }
    }
    
    return {
      isValid: isFormValid,
      fields: results
    }
  }
}

// 使用表单验证器
const validator = new FormValidator()
validator.addField('email', new EmailValidation())
validator.addField('password', new PasswordValidation(10))

const formData = {
  email: 'user@example.com',
  password: 'MyPassword123!'
}

const validationResult = validator.validate(formData)
console.log('Validation result:', validationResult)

总结

JavaScript设计模式的核心要点:

  1. 创建型模式:单例、工厂、建造者模式解决对象创建问题
  2. 行为型模式:观察者、策略模式解决对象间交互问题
  3. 结构型模式:适配器、装饰器模式解决对象组合问题
  4. 现代应用:结合ES6+特性和现代开发需求
  5. 实战价值:提高代码可维护性、可扩展性和可复用性

设计模式不是银弹,需要根据具体场景选择合适的模式,避免过度设计。重要的是理解模式背后的思想,灵活运用到实际开发中。