探索如何运用现代JavaScript设计模式和架构原则构建健壮、可扩展的前端应用
JavaScript设计模式概述
设计模式是解决常见软件设计问题的可重用方案。在JavaScript中,设计模式的应用可以帮助我们创建更加模块化、可维护和可扩展的代码结构。
为什么需要设计模式?
- 提高代码的可读性和可维护性
- 促进团队协作和代码复用
- 降低系统各部分之间的耦合度
- 提供经过验证的解决方案
创建型设计模式
工厂模式 (Factory Pattern)
工厂模式提供了一种创建对象的接口,而不需要指定具体的类。
// 用户工厂示例 class UserFactory { static createUser(type, userData) { switch (type) { case 'admin': return new AdminUser(userData); case 'customer': return new CustomerUser(userData); case 'moderator': return new ModeratorUser(userData); default: throw new Error('未知的用户类型'); } } } class AdminUser { constructor(data) { this.role = 'admin'; this.permissions = ['create', 'read', 'update', 'delete', 'manage_users']; Object.assign(this, data); } } class CustomerUser { constructor(data) { this.role = 'customer'; this.permissions = ['read', 'purchase']; Object.assign(this, data); } } // 使用工厂 const admin = UserFactory.createUser('admin', { name: '张三', email: 'zhang@example.com' }); console.log(admin); // AdminUser实例
单例模式 (Singleton Pattern)
确保一个类只有一个实例,并提供全局访问点。
// 应用配置单例 class AppConfig { constructor() { if (AppConfig.instance) { return AppConfig.instance; } this.settings = { apiUrl: 'https://api.example.com', theme: 'dark', language: 'zh-CN', maxConnections: 10 }; AppConfig.instance = this; return this; } static getInstance() { if (!AppConfig.instance) { AppConfig.instance = new AppConfig(); } return AppConfig.instance; } getSetting(key) { return this.settings[key]; } setSetting(key, value) { this.settings[key] = value; this.saveToStorage(); } saveToStorage() { localStorage.setItem('appConfig', JSON.stringify(this.settings)); } loadFromStorage() { const saved = localStorage.getItem('appConfig'); if (saved) { this.settings = { ...this.settings, ...JSON.parse(saved) }; } } } // 使用单例 const config1 = new AppConfig(); const config2 = new AppConfig(); console.log(config1 === config2); // true config1.setSetting('theme', 'light'); console.log(config2.getSetting('theme')); // 'light'
结构型设计模式
装饰器模式 (Decorator Pattern)
动态地给对象添加额外的职责,而不改变其结构。
// 基础日志器类 class Logger { log(message) { console.log(`基础日志: ${message}`); } } // 装饰器基类 class LoggerDecorator { constructor(logger) { this.logger = logger; } log(message) { this.logger.log(message); } } // 时间戳装饰器 class TimestampDecorator extends LoggerDecorator { log(message) { const timestamp = new Date().toISOString(); super.log(`[${timestamp}] ${message}`); } } // 级别装饰器 class LevelDecorator extends LoggerDecorator { constructor(logger, level = 'INFO') { super(logger); this.level = level; } log(message) { super.log(`[${this.level}] ${message}`); } } // 使用装饰器 let logger = new Logger(); logger = new TimestampDecorator(logger); logger = new LevelDecorator(logger, 'DEBUG'); logger.log('用户登录成功'); // 输出: [DEBUG] [2023-11-10T10:30:00.000Z] 用户登录成功
适配器模式 (Adapter Pattern)
使接口不兼容的对象能够相互合作。
// 第三方支付服务(不兼容的接口) class ThirdPartyPayment { makePayment(amount, currency, recipient) { console.log(`支付 ${amount} ${currency} 给 ${recipient}`); return Math.random().toString(36).substr(2, 9); // 模拟交易ID } } // 我们的支付接口 class PaymentService { pay(amount, options = {}) { throw new Error('必须实现pay方法'); } } // 适配器 class PaymentAdapter extends PaymentService { constructor(thirdPartyPayment) { super(); this.thirdPartyPayment = thirdPartyPayment; } pay(amount, options = {}) { const { currency = 'USD', recipient = 'default-recipient', description = '' } = options; const transactionId = this.thirdPartyPayment.makePayment( amount, currency, recipient ); return { success: true, transactionId, amount, currency, timestamp: new Date(), description }; } } // 使用适配器 const thirdPartyPayment = new ThirdPartyPayment(); const paymentService = new PaymentAdapter(thirdPartyPayment); const result = paymentService.pay(100, { currency: 'CNY', recipient: '商家A', description: '购买商品' }); console.log(result);
行为型设计模式
观察者模式 (Observer Pattern)
定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会收到通知。
// 主题(被观察者) class Subject { constructor() { this.observers = []; this.state = null; } addObserver(observer) { this.observers.push(observer); } removeObserver(observer) { this.observers = this.observers.filter(obs => obs !== observer); } notifyObservers() { this.observers.forEach(observer => { observer.update(this.state); }); } setState(state) { this.state = state; this.notifyObservers(); } } // 观察者接口 class Observer { update(state) { throw new Error('必须实现update方法'); } } // 具体观察者 class LoggerObserver extends Observer { update(state) { console.log(`状态更新: ${JSON.stringify(state)}`); } } class StorageObserver extends Observer { update(state) { localStorage.setItem('appState', JSON.stringify(state)); } } class UIObserver extends Observer { constructor(elementId) { super(); this.element = document.getElementById(elementId); } update(state) { if (this.element) { this.element.textContent = JSON.stringify(state, null, 2); } } } // 使用观察者模式 const subject = new Subject(); subject.addObserver(new LoggerObserver()); subject.addObserver(new StorageObserver()); subject.addObserver(new UIObserver('state-display')); // 状态改变会自动通知所有观察者 subject.setState({ user: '张三', isLoggedIn: true }); subject.setState({ user: '张三', isLoggedIn: true, theme: 'dark' });
策略模式 (Strategy Pattern)
定义一系列算法,将它们封装起来,并且使它们可以相互替换。
// 策略接口 class ValidationStrategy { validate(value) { throw new Error('必须实现validate方法'); } } // 具体策略 class EmailValidation extends ValidationStrategy { validate(value) { const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/; return emailRegex.test(value); } } class PhoneValidation extends ValidationStrategy { validate(value) { const phoneRegex = /^1[3-9]d{9}$/; return phoneRegex.test(value); } } class RequiredValidation extends ValidationStrategy { validate(value) { return value !== undefined && value !== null && value !== ''; } } class MinLengthValidation extends ValidationStrategy { constructor(minLength) { super(); this.minLength = minLength; } validate(value) { return value && value.length >= this.minLength; } } // 验证上下文 class Validator { constructor() { this.strategies = []; } addStrategy(strategy) { this.strategies.push(strategy); } validate(value) { const errors = []; this.strategies.forEach((strategy, index) => { if (!strategy.validate(value)) { errors.push(`验证策略 ${index + 1} 失败`); } }); return { isValid: errors.length === 0, errors }; } } // 使用策略模式 const emailValidator = new Validator(); emailValidator.addStrategy(new RequiredValidation()); emailValidator.addStrategy(new EmailValidation()); const passwordValidator = new Validator(); passwordValidator.addStrategy(new RequiredValidation()); passwordValidator.addStrategy(new MinLengthValidation(6)); // 测试验证 console.log(emailValidator.validate('test@example.com')); console.log(emailValidator.validate('invalid-email')); console.log(passwordValidator.validate('short')); console.log(passwordValidator.validate('longenough'));
前端应用架构模式
MVVM架构 (Model-View-ViewModel)
MVVM模式将用户界面与业务逻辑分离,通过数据绑定实现自动同步。
// 简单的MVVM实现 class Observable { constructor() { this._value = null; this._listeners = []; } get value() { return this._value; } set value(newValue) { if (this._value !== newValue) { this._value = newValue; this._notifyListeners(); } } subscribe(listener) { this._listeners.push(listener); } _notifyListeners() { this._listeners.forEach(listener => listener(this._value)); } } // ViewModel class UserViewModel { constructor() { this.name = new Observable(); this.email = new Observable(); this.isValid = new Observable(); // 自动验证 this.name.subscribe(() => this._validate()); this.email.subscribe(() => this._validate()); } _validate() { const nameValid = this.name.value && this.name.value.length >= 2; const emailValid = this.email.value && this.email.value.includes('@'); this.isValid.value = nameValid && emailValid; } toModel() { return { name: this.name.value, email: this.email.value }; } } // 视图绑定 function bindInputToObservable(inputElement, observable) { inputElement.value = observable.value || ''; inputElement.addEventListener('input', (e) => { observable.value = e.target.value; }); observable.subscribe(value => { if (inputElement.value !== value) { inputElement.value = value || ''; } }); } // 使用MVVM const viewModel = new UserViewModel(); // 绑定UI元素 bindInputToObservable(document.getElementById('name-input'), viewModel.name); bindInputToObservable(document.getElementById('email-input'), viewModel.email); // 监听验证状态 viewModel.isValid.subscribe(isValid => { document.getElementById('submit-btn').disabled = !isValid; });
实战案例:电商购物车系统
需求分析
构建一个完整的电商购物车系统,包含以下功能:
- 商品添加、删除、数量修改
- 价格计算(包括折扣、税费、运费)
- 库存验证
- 持久化存储
- 优惠券应用
实现代码
// 购物车项 class CartItem { constructor(product, quantity = 1) { this.product = product; this.quantity = quantity; } get totalPrice() { return this.product.price * this.quantity; } increaseQuantity(amount = 1) { this.quantity += amount; } decreaseQuantity(amount = 1) { this.quantity = Math.max(0, this.quantity - amount); } } // 购物车 class ShoppingCart { constructor() { this.items = new Map(); this.coupons = new Set(); this.taxRate = 0.08; // 8%税率 this.shippingCost = 5.99; } addItem(product, quantity = 1) { if (this.items.has(product.id)) { this.items.get(product.id).increaseQuantity(quantity); } else { this.items.set(product.id, new CartItem(product, quantity)); } this._saveToStorage(); } removeItem(productId) { this.items.delete(productId); this._saveToStorage(); } updateQuantity(productId, quantity) { const item = this.items.get(productId); if (item) { if (quantity <= 0) { this.removeItem(productId); } else { item.quantity = quantity; this._saveToStorage(); } } } applyCoupon(code) { this.coupons.add(code); this._saveToStorage(); } removeCoupon(code) { this.coupons.delete(code); this._saveToStorage(); } get subtotal() { let total = 0; for (const item of this.items.values()) { total += item.totalPrice; } return total; } get discount() { // 简单的折扣计算逻辑 let discount = 0; if (this.coupons.has('SAVE10')) { discount += this.subtotal * 0.1; } if (this.coupons.has('FREESHIPPING')) { discount += this.shippingCost; } return discount; } get tax() { return (this.subtotal - this.discount) * this.taxRate; } get total() { return this.subtotal - this.discount + this.tax + this.shippingCost; } get itemCount() { let count = 0; for (const item of this.items.values()) { count += item.quantity; } return count; } clear() { this.items.clear(); this.coupons.clear(); this._saveToStorage(); } _saveToStorage() { const cartData = { items: Array.from(this.items.entries()), coupons: Array.from(this.coupons), timestamp: new Date().toISOString() }; localStorage.setItem('shoppingCart', JSON.stringify(cartData)); } loadFromStorage() { const saved = localStorage.getItem('shoppingCart'); if (saved) { const cartData = JSON.parse(saved); this.items = new Map(cartData.items); this.coupons = new Set(cartData.coupons); } } // 迭代器支持 [Symbol.iterator]() { return this.items.values(); } } // 商品类 class Product { constructor(id, name, price, stock = 0) { this.id = id; this.name = name; this.price = price; this.stock = stock; } } // 使用示例 const cart = new ShoppingCart(); // 添加商品 const product1 = new Product(1, 'JavaScript高级编程', 89.99, 10); const product2 = new Product(2, 'CSS权威指南', 79.99, 5); cart.addItem(product1, 2); cart.addItem(product2, 1); // 应用优惠券 cart.applyCoupon('SAVE10'); console.log('商品数量:', cart.itemCount); console.log('小计:', cart.subtotal.toFixed(2)); console.log('折扣:', cart.discount.toFixed(2)); console.log('税费:', cart.tax.toFixed(2)); console.log('总计:', cart.total.toFixed(2)); // 支持迭代 for (const item of cart) { console.log(`${item.product.name} x ${item.quantity}`); }