探索如何运用现代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}`);
}

