Node.js高级设计模式
设计模式是解决软件设计中常见问题的可复用方案。在Node.js应用开发中,合理应用设计模式可以提高代码的可维护性、可扩展性和可读性。本章节将深入探讨Node.js中常用的高级设计模式,包括它们的原理、实现方式以及在实际项目中的应用场景。
一、创建型设计模式
创建型设计模式专注于对象的创建机制,帮助我们在不直接使用new操作符的情况下,更加灵活地创建对象。
1.1 工厂模式
工厂模式通过一个共同的接口来创建不同类型的对象,隐藏了具体对象的创建细节。
// 1. 简单工厂模式
class DatabaseFactory {
static createDatabase(type, config) {
switch (type.toLowerCase()) {
case 'mysql':
return new MySQLDatabase(config);
case 'mongodb':
return new MongoDBDatabase(config);
case 'postgres':
return new PostgresDatabase(config);
default:
throw new Error(`Unsupported database type: ${type}`);
}
}
}
// 数据库接口
class Database {
async connect() { throw new Error('Method not implemented'); }
async query() { throw new Error('Method not implemented'); }
async disconnect() { throw new Error('Method not implemented'); }
}
// MySQL实现
class MySQLDatabase extends Database {
constructor(config) {
super();
this.config = config;
this.connection = null;
}
async connect() {
console.log('Connecting to MySQL database...');
// 实际连接逻辑
this.connection = { connected: true, type: 'mysql' };
return this.connection;
}
async query(sql, params) {
console.log(`Executing MySQL query: ${sql} with params:`, params);
return [{ id: 1, name: 'Example' }];
}
async disconnect() {
console.log('Disconnecting from MySQL database...');
this.connection = null;
}
}
// MongoDB实现(略)
class MongoDBDatabase extends Database { /* 实现细节 */ }
// 使用示例
async function useDatabase() {
// 从配置中获取数据库类型
const dbType = process.env.DB_TYPE || 'mysql';
const dbConfig = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
};
// 使用工厂创建数据库实例
const db = DatabaseFactory.createDatabase(dbType, dbConfig);
try {
await db.connect();
const results = await db.query('SELECT * FROM users LIMIT 10');
console.log('Query results:', results);
} finally {
await db.disconnect();
}
}
// 2. 工厂方法模式
// 更灵活的工厂实现,允许子类决定实例化的对象类型
class Logger {
log(message) { throw new Error('Method not implemented'); }
info(message) { throw new Error('Method not implemented'); }
error(message) { throw new Error('Method not implemented'); }
}
class ConsoleLogger extends Logger {
log(message) { console.log(`[LOG] ${message}`); }
info(message) { console.info(`[INFO] ${message}`); }
error(message) { console.error(`[ERROR] ${message}`); }
}
class FileLogger extends Logger {
constructor(filePath) {
super();
this.filePath = filePath;
}
log(message) { /* 写入文件的实现 */ }
info(message) { /* 写入文件的实现 */ }
error(message) { /* 写入文件的实现 */ }
}
// 抽象日志工厂
class LoggerFactory {
createLogger() { throw new Error('Method not implemented'); }
}
// 具体工厂实现
class ConsoleLoggerFactory extends LoggerFactory {
createLogger() {
return new ConsoleLogger();
}
}
class FileLoggerFactory extends LoggerFactory {
constructor(filePath) {
super();
this.filePath = filePath;
}
createLogger() {
return new FileLogger(this.filePath);
}
}
// 使用工厂方法
function setupLogger() {
const loggerType = process.env.LOGGER_TYPE || 'console';
let factory;
if (loggerType === 'file') {
factory = new FileLoggerFactory('app.log');
} else {
factory = new ConsoleLoggerFactory();
}
return factory.createLogger();
}
const logger = setupLogger();
logger.info('Application started');
1.2 单例模式
单例模式确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在Node.js中,模块系统本身就提供了单例的特性。
// 1. 利用Node.js模块系统实现单例
// logger.js
const winston = require('winston');
// 模块级别的变量,会被缓存
let loggerInstance = null;
function createLogger() {
if (!loggerInstance) {
loggerInstance = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'app.log' })
]
});
}
return loggerInstance;
}
module.exports = createLogger();
// 使用示例
// const logger = require('./logger'); // 每次都返回同一个实例
// logger.info('This is a log message');
// 2. 传统单例模式实现
class ConfigManager {
constructor() {
if (ConfigManager.instance) {
return ConfigManager.instance;
}
// 初始化配置
this.config = {};
this.loadConfig();
// 保存实例引用
ConfigManager.instance = this;
}
loadConfig() {
// 从环境变量、配置文件等加载配置
this.config = {
apiKey: process.env.API_KEY,
dbUrl: process.env.DB_URL,
timeout: parseInt(process.env.TIMEOUT, 10) || 30000,
maxConnections: parseInt(process.env.MAX_CONNECTIONS, 10) || 10,
// 其他配置项...
};
}
get(key, defaultValue = null) {
return this.config[key] !== undefined ? this.config[key] : defaultValue;
}
set(key, value) {
this.config[key] = value;
}
// 静态方法获取实例
static getInstance() {
if (!ConfigManager.instance) {
ConfigManager.instance = new ConfigManager();
}
return ConfigManager.instance;
}
}
// 使用示例
const config1 = new ConfigManager();
const config2 = new ConfigManager();
console.log(config1 === config2); // true,同一个实例
// 或使用静态方法
const config = ConfigManager.getInstance();
// 3. 懒加载单例模式
class DatabaseConnection {
constructor() {
this.connection = null;
}
async connect() {
if (!this.connection) {
console.log('Creating database connection...');
// 模拟异步连接
this.connection = await new Promise((resolve) => {
setTimeout(() => {
resolve({ id: 'db-connection-1', status: 'connected' });
}, 1000);
});
}
return this.connection;
}
async query(sql) {
const conn = await this.connect();
console.log(`Executing query with connection ${conn.id}: ${sql}`);
return [{ id: 1, name: 'Result' }];
}
async disconnect() {
if (this.connection) {
console.log('Closing database connection...');
this.connection = null;
}
}
}
// 导出单例实例
module.exports = new DatabaseConnection();
// 使用示例
// const db = require('./database-connection');
// async function fetchData() {
// const results = await db.query('SELECT * FROM users');
// return results;
// }
1.3 原型模式
原型模式通过复制现有对象来创建新对象,而不是通过实例化类。在JavaScript中,原型继承是语言的核心特性。
// 1. 基本原型模式
class UserPrototype {
constructor(user) {
this.username = user.username;
this.email = user.email;
this.role = user.role || 'user';
this.createdAt = user.createdAt || new Date();
}
// 克隆方法
clone() {
// 创建一个新对象,复制当前对象的属性
const clonedUser = {
username: this.username,
email: this.email,
role: this.role,
createdAt: new Date(this.createdAt)
};
return new UserPrototype(clonedUser);
}
// 修改属性的方法
withUsername(username) {
const clone = this.clone();
clone.username = username;
return clone;
}
withEmail(email) {
const clone = this.clone();
clone.email = email;
return clone;
}
withRole(role) {
const clone = this.clone();
clone.role = role;
return clone;
}
}
// 使用示例
const adminPrototype = new UserPrototype({
username: 'admin',
email: 'admin@example.com',
role: 'admin'
});
// 创建新的管理员用户,基于原型但有不同属性
const newAdmin = adminPrototype
.withUsername('superadmin')
.withEmail('superadmin@example.com');
console.log(newAdmin); // UserPrototype { username: 'superadmin', email: 'superadmin@example.com', role: 'admin', ... }
// 2. 原型注册表
class PrototypeRegistry {
constructor() {
this.prototypes = {};
}
register(name, prototype) {
this.prototypes[name] = prototype;
}
unregister(name) {
delete this.prototypes[name];
}
get(name) {
const prototype = this.prototypes[name];
if (!prototype) {
throw new Error(`Prototype '${name}' not found`);
}
return prototype.clone();
}
listPrototypes() {
return Object.keys(this.prototypes);
}
}
// 使用原型注册表
const userRegistry = new PrototypeRegistry();
// 注册原型
userRegistry.register('standard', new UserPrototype({
username: 'user',
email: 'user@example.com',
role: 'user'
}));
userRegistry.register('admin', new UserPrototype({
username: 'admin',
email: 'admin@example.com',
role: 'admin'
}));
userRegistry.register('guest', new UserPrototype({
username: 'guest',
email: 'guest@example.com',
role: 'guest'
}));
// 从注册表获取并克隆原型
const guestUser = userRegistry.get('guest');
console.log(guestUser.role); // 'guest'
// 创建自定义用户
const customUser = userRegistry.get('standard')
.withUsername('johndoe')
.withEmail('john@example.com');
// 3. 深度克隆原型
function deepClone(obj) {
// 处理null和基本类型
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理日期对象
if (obj instanceof Date) {
return new Date(obj.getTime());
}
// 处理数组
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
// 处理正则表达式
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}
// 处理普通对象
const clonedObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
// 增强原型模式以支持深度克隆
class ComplexPrototype {
constructor(data) {
this.data = data;
}
deepClone() {
return new ComplexPrototype(deepClone(this.data));
}
}
// 使用示例
const original = new ComplexPrototype({
name: 'Complex Object',
settings: {
theme: 'dark',
notifications: true
},
tags: ['prototype', 'design', 'pattern'],
createdAt: new Date()
});
const cloned = original.deepClone();
cloned.data.settings.theme = 'light'; // 修改克隆对象不会影响原始对象
console.log(original.data.settings.theme); // 'dark'
console.log(cloned.data.settings.theme); // 'light'
1.4 构建者模式
构建者模式用于创建复杂对象,将对象的构建过程与表示分离,允许同样的构建过程创建不同的表示。
// 1. 基本构建者模式
class RequestBuilder {
constructor() {
this.request = {
method: 'GET',
url: '',
headers: {},
body: null,
queryParams: {},
timeout: 30000,
retry: {
enabled: false,
maxRetries: 3,
delay: 1000
}
};
}
setMethod(method) {
this.request.method = method;
return this;
}
setUrl(url) {
this.request.url = url;
return this;
}
addHeader(name, value) {
this.request.headers[name] = value;
return this;
}
setBody(body) {
this.request.body = body;
return this;
}
addQueryParam(name, value) {
this.request.queryParams[name] = value;
return this;
}
setTimeout(timeout) {
this.request.timeout = timeout;
return this;
}
enableRetry(maxRetries = 3, delay = 1000) {
this.request.retry = {
enabled: true,
maxRetries,
delay
};
return this;
}
build() {
// 验证必要的字段
if (!this.request.url) {
throw new Error('URL is required');
}
// 返回请求对象的副本
return { ...this.request };
}
}
// 使用示例
const request = new RequestBuilder()
.setMethod('POST')
.setUrl('https://api.example.com/users')
.addHeader('Content-Type', 'application/json')
.addHeader('Authorization', 'Bearer token123')
.setBody({ name: 'John Doe', email: 'john@example.com' })
.setTimeout(5000)
.enableRetry(5, 2000)
.build();
console.log(request);
// { method: 'POST', url: 'https://api.example.com/users', headers: { ... }, ... }
// 2. 建造者模式与工厂模式结合
class ApiClient {
constructor(config) {
this.baseUrl = config.baseUrl;
this.defaultHeaders = config.defaultHeaders || {};
this.timeout = config.timeout || 30000;
}
// 创建请求构建器
createRequest() {
const builder = new RequestBuilder();
// 设置默认值
builder.setTimeout(this.timeout);
// 添加默认头
for (const [key, value] of Object.entries(this.defaultHeaders)) {
builder.addHeader(key, value);
}
return builder;
}
// 发送请求
async sendRequest(requestConfig) {
try {
console.log(`Sending ${requestConfig.method} request to ${requestConfig.url}`);
// 实际的请求逻辑
// const response = await fetch(requestConfig.url, {
// method: requestConfig.method,
// headers: requestConfig.headers,
// body: requestConfig.body ? JSON.stringify(requestConfig.body) : null,
// });
// return response.json();
// 模拟响应
return { success: true, data: { id: 1, ...requestConfig.body } };
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
}
// 使用示例
const apiClient = new ApiClient({
baseUrl: 'https://api.example.com',
defaultHeaders: {
'Content-Type': 'application/json',
'X-Client': 'Node.js-Api-Client/1.0'
},
timeout: 10000
});
// 创建并发送请求
async function createUser(userData) {
const request = apiClient.createRequest()
.setMethod('POST')
.setUrl(apiClient.baseUrl + '/users')
.setBody(userData)
.enableRetry(3, 1000)
.build();
return await apiClient.sendRequest(request);
}
// 3. 复合构建者模式
class DocumentBuilder {
constructor() {
this.document = {
title: '',
sections: [],
metadata: {},
format: 'html'
};
}
setTitle(title) {
this.document.title = title;
return this;
}
setFormat(format) {
if (!['html', 'markdown', 'pdf'].includes(format)) {
throw new Error('Unsupported format');
}
this.document.format = format;
return this;
}
addMetadata(key, value) {
this.document.metadata[key] = value;
return this;
}
// 创建并添加一个新的章节
addSection(title, content) {
this.document.sections.push({ title, content });
return this;
}
// 获取章节构建器
sectionBuilder() {
const sectionBuilder = new SectionBuilder(this);
return sectionBuilder;
}
build() {
// 验证文档
if (!this.document.title) {
throw new Error('Document title is required');
}
if (this.document.sections.length === 0) {
throw new Error('Document must have at least one section');
}
return { ...this.document };
}
}
// 章节构建器
class SectionBuilder {
constructor(documentBuilder) {
this.documentBuilder = documentBuilder;
this.section = { title: '', content: '', subsections: [] };
}
setTitle(title) {
this.section.title = title;
return this;
}
setContent(content) {
this.section.content = content;
return this;
}
addSubsection(title, content) {
this.section.subsections.push({ title, content });
return this;
}
// 完成章节并返回文档构建器
endSection() {
this.documentBuilder.document.sections.push(this.section);
return this.documentBuilder;
}
}
// 使用复合构建者
const document = new DocumentBuilder()
.setTitle('Design Patterns in Node.js')
.setFormat('markdown')
.addMetadata('author', 'John Doe')
.addMetadata('date', new Date().toISOString())
.sectionBuilder()
.setTitle('Introduction')
.setContent('This document describes design patterns in Node.js.')
.endSection()
.sectionBuilder()
.setTitle('Creational Patterns')
.setContent('Creational patterns focus on object creation mechanisms.')
.addSubsection('Factory Pattern', 'Creates objects without specifying the exact class.')
.addSubsection('Singleton Pattern', 'Ensures a class has only one instance.')
.endSection()
.build();
console.log(document);
二、结构型设计模式
结构型设计模式关注类和对象的组合,帮助我们解决如何将对象和类组装成更大的结构。
2.1 适配器模式
适配器模式允许接口不兼容的对象能够相互合作,将一个类的接口转换成客户端所期望的另一个接口。
// 1. 基本适配器模式
class LegacyLogger {
logMessage(severity, message) {
console.log(`[${severity.toUpperCase()}] ${message}`);
}
logError(error) {
console.error(`[ERROR] ${error.message}`);
}
}
// 新的日志接口
class ModernLogger {
info(message) { throw new Error('Method not implemented'); }
warning(message) { throw new Error('Method not implemented'); }
error(message) { throw new Error('Method not implemented'); }
debug(message) { throw new Error('Method not implemented'); }
}
// 适配器:使旧的日志器适应新的接口
class LoggerAdapter extends ModernLogger {
constructor(legacyLogger) {
super();
this.legacyLogger = legacyLogger;
}
info(message) {
this.legacyLogger.logMessage('info', message);
}
warning(message) {
this.legacyLogger.logMessage('warning', message);
}
error(message) {
// 如果是Error对象,使用logError方法
if (message instanceof Error) {
this.legacyLogger.logError(message);
} else {
this.legacyLogger.logMessage('error', message);
}
}
debug(message) {
// 旧的日志器没有debug级别,降级为info
this.legacyLogger.logMessage('info', `[DEBUG] ${message}`);
}
}
// 使用示例
const legacyLogger = new LegacyLogger();
const logger = new LoggerAdapter(legacyLogger);
// 现在可以使用新的接口,但底层实现仍然是旧的日志器
logger.info('Application started');
logger.warning('Low memory warning');
logger.error(new Error('Database connection failed'));
logger.debug('Processing item #123');
// 2. 数据库适配器
class DatabaseAdapter {
constructor(database) {
this.database = database;
}
// 统一的查询接口
async query(query, params = []) {
if (this.database.query) {
// 支持query方法的数据库
return await this.database.query(query, params);
} else if (this.database.execute) {
// 支持execute方法的数据库
return await this.database.execute(query, params);
} else if (this.database.run) {
// 支持run方法的数据库
return await this.database.run(query, params);
}
throw new Error('Unsupported database interface');
}
// 统一的连接接口
async connect() {
if (this.database.connect) {
return await this.database.connect();
} else if (this.database.open) {
return await this.database.open();
}
throw new Error('Unsupported connection method');
}
// 统一的断开连接接口
async disconnect() {
if (this.database.disconnect) {
return await this.database.disconnect();
} else if (this.database.close) {
return await this.database.close();
}
throw new Error('Unsupported disconnection method');
}
}
// 使用示例
async function useDatabase(database) {
const dbAdapter = new DatabaseAdapter(database);
try {
await dbAdapter.connect();
const results = await dbAdapter.query('SELECT * FROM users LIMIT 10');
console.log('Query results:', results);
} catch (error) {
console.error('Database error:', error);
} finally {
await dbAdapter.disconnect();
}
}
// 3. API适配器
class ExternalApiAdapter {
constructor(externalApiClient, options = {}) {
this.client = externalApiClient;
this.options = options;
}
// 转换请求格式
async fetchUserData(userId) {
try {
// 调用外部API
const response = await this.client.getUserById(userId);
// 转换响应格式为内部系统所需的格式
return {
id: response.user_id,
name: response.full_name,
email: response.email_address,
profile: {
avatar: response.profile_image,
bio: response.biography,
location: response.location
},
createdAt: new Date(response.registration_date),
lastActive: new Date(response.last_login_date)
};
} catch (error) {
console.error(`Failed to fetch user data: ${error}`);
// 统一错误处理
throw new Error(`User data service error: ${error.message}`);
}
}
// 批处理多个请求
async fetchMultipleUsers(userIds) {
try {
// 并行请求多个用户数据
const promises = userIds.map(id => this.fetchUserData(id));
const results = await Promise.all(promises);
return results;
} catch (error) {
console.error(`Batch user data fetch failed: ${error}`);
throw error;
}
}
// 缓存结果以提高性能
async getCachedUserData(userId, cacheTtl = 3600000) { // 默认缓存1小时
const cacheKey = `user_${userId}`;
// 尝试从缓存获取
if (this.options.cache && await this.options.cache.has(cacheKey)) {
const cachedData = await this.options.cache.get(cacheKey);
console.log(`Returning cached user data for ${userId}`);
return cachedData;
}
// 缓存未命中,获取新数据
const userData = await this.fetchUserData(userId);
// 存入缓存
if (this.options.cache) {
await this.options.cache.set(cacheKey, userData, cacheTtl);
}
return userData;
}
}
// 使用示例
const memoryCache = {
cache: new Map(),
async has(key) {
return this.cache.has(key);
},
async get(key) {
return this.cache.get(key);
},
async set(key, value, ttl) {
this.cache.set(key, value);
// 设置过期时间
setTimeout(() => {
this.cache.delete(key);
}, ttl);
}
};
// 模拟外部API客户端
const externalApiClient = {
async getUserById(id) {
// 模拟API调用延迟
await new Promise(resolve => setTimeout(resolve, 100));
// 模拟返回数据
return {
user_id: id,
full_name: `User ${id}`,
email_address: `user${id}@example.com`,
profile_image: `https://example.com/avatars/${id}.jpg`,
biography: `This is user ${id}'s profile.`,
location: 'Unknown',
registration_date: new Date(Date.now() - id * 1000000).toISOString(),
last_login_date: new Date().toISOString()
};
}
};
// 创建适配器实例
const apiAdapter = new ExternalApiAdapter(externalApiClient, { cache: memoryCache });
// 使用适配器
async function getUserDataDemo() {
const userId = 123;
// 第一次请求(无缓存)
console.time('First request');
const user1 = await apiAdapter.getCachedUserData(userId);
console.timeEnd('First request');
console.log('User data:', user1);
// 第二次请求(有缓存)
console.time('Second request');
const user2 = await apiAdapter.getCachedUserData(userId);
console.timeEnd('Second request');
// 批量请求
const batchResults = await apiAdapter.fetchMultipleUsers([1, 2, 3]);
console.log('Batch results:', batchResults.length, 'users');
}
2.2 装饰器模式
装饰器模式动态地给对象添加额外的责任,提供了比继承更有弹性的扩展功能的方式。在JavaScript中,装饰器语法已经成为ES提案的一部分。
// 1. 基本装饰器模式
class Coffee {
cost() {
return 5;
}
description() {
return 'Simple Coffee';
}
}
// 装饰器基类
class CoffeeDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost();
}
description() {
return this.coffee.description();
}
}
// 具体装饰器:牛奶
class MilkDecorator extends CoffeeDecorator {
cost() {
return this.coffee.cost() + 1;
}
description() {
return `${this.coffee.description()}, Milk`;
}
}
// 具体装饰器:糖
class SugarDecorator extends CoffeeDecorator {
cost() {
return this.coffee.cost() + 0.5;
}
description() {
return `${this.coffee.description()}, Sugar`;
}
}
// 具体装饰器:奶泡
class FoamDecorator extends CoffeeDecorator {
cost() {
return this.coffee.cost() + 1.5;
}
description() {
return `${this.coffee.description()}, Foam`;
}
}
// 使用示例
let myCoffee = new Coffee();
console.log(`${myCoffee.description()}: $${myCoffee.cost()}`); // Simple Coffee: $5
// 添加牛奶和糖
myCoffee = new MilkDecorator(myCoffee);
myCoffee = new SugarDecorator(myCoffee);
console.log(`${myCoffee.description()}: $${myCoffee.cost()}`); // Simple Coffee, Milk, Sugar: $6.5
// 添加奶泡
myCoffee = new FoamDecorator(myCoffee);
console.log(`${myCoffee.description()}: $${myCoffee.cost()}`); // Simple Coffee, Milk, Sugar, Foam: $8
// 2. 函数装饰器
function logExecution(target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.log(`Executing ${propertyKey} with arguments:`, args);
const startTime = Date.now();
try {
const result = originalMethod.apply(this, args);
const executionTime = Date.now() - startTime;
console.log(`${propertyKey} executed in ${executionTime}ms with result:`, result);
return result;
} catch (error) {
console.error(`${propertyKey} failed with error:`, error);
throw error;
}
};
return descriptor;
}
// 使用函数装饰器
class DataProcessor {
@logExecution
processData(data) {
// 模拟数据处理
console.log('Processing data...');
return data.map(item => item * 2);
}
@logExecution
async fetchData(url) {
// 模拟异步数据获取
console.log(`Fetching data from ${url}...`);
await new Promise(resolve => setTimeout(resolve, 100));
return [1, 2, 3, 4, 5];
}
}
// 注意:在Node.js中使用装饰器语法需要Babel或TypeScript配置
// 3. 中间件作为装饰器
class ExpressApp {
constructor() {
this.middlewares = [];
this.routes = new Map();
}
// 添加中间件(装饰器)
use(middleware) {
this.middlewares.push(middleware);
return this;
}
// 注册路由
get(path, handler) {
this.routes.set(`GET ${path}`, handler);
return this;
}
post(path, handler) {
this.routes.set(`POST ${path}`, handler);
return this;
}
// 模拟处理请求
async handleRequest(method, path, request, response) {
const routeKey = `${method} ${path}`;
const handler = this.routes.get(routeKey);
if (!handler) {
response.status = 404;
response.body = { error: 'Not found' };
return;
}
// 创建请求上下文
const ctx = {
request,
response,
next: () => {} // 简化版next函数
};
try {
// 先执行所有中间件
for (const middleware of this.middlewares) {
await middleware(ctx, ctx.next);
}
// 然后执行路由处理程序
await handler(ctx.request, ctx.response);
} catch (error) {
response.status = 500;
response.body = { error: error.message };
console.error('Request handling error:', error);
}
}
}
// 中间件装饰器示例
const loggerMiddleware = async (ctx, next) => {
const startTime = Date.now();
console.log(`[${new Date().toISOString()}] ${ctx.request.method} ${ctx.request.url}`);
await next();
const duration = Date.now() - startTime;
console.log(`[${new Date().toISOString()}] ${ctx.request.method} ${ctx.request.url} ${ctx.response.status} ${duration}ms`);
};
const authMiddleware = async (ctx, next) => {
const authHeader = ctx.request.headers.authorization;
if (!authHeader) {
ctx.response.status = 401;
ctx.response.body = { error: 'Unauthorized' };
return;
}
// 简化的认证逻辑
if (authHeader !== 'Bearer valid-token') {
ctx.response.status = 403;
ctx.response.body = { error: 'Forbidden' };
return;
}
// 设置用户信息
ctx.request.user = { id: 1, name: 'Authenticated User' };
await next();
};
// 使用示例
const app = new ExpressApp();
// 添加中间件装饰器
app.use(loggerMiddleware);
app.use(authMiddleware);
// 定义路由
app.get('/api/users', (req, res) => {
res.status = 200;
res.body = {
users: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' }
],
authenticatedUser: req.user
};
});
// 模拟请求
async function simulateRequest() {
const request = {
method: 'GET',
url: '/api/users',
headers: {
authorization: 'Bearer valid-token'
}
};
const response = {};
await app.handleRequest('GET', '/api/users', request, response);
console.log('Response:', response);
}
2.3 代理模式
代理模式为另一个对象提供一个代理或占位符,以控制对这个对象的访问。在Node.js中,代理模式常用于实现延迟加载、访问控制、缓存等功能。
// 1. 基本代理模式
class Image {
constructor(filename) {
this.filename = filename;
this.loadImage();
}
loadImage() {
console.log(`Loading image from ${this.filename}...`);
// 模拟加载大图像的耗时操作
this.data = `Image data for ${this.filename}`;
}
display() {
console.log(`Displaying ${this.filename}: ${this.data}`);
}
}
// 图像代理:延迟加载
class ImageProxy {
constructor(filename) {
this.filename = filename;
this.image = null;
}
// 延迟加载图像
loadImage() {
if (!this.image) {
this.image = new Image(this.filename);
}
}
// 控制对display方法的访问
display() {
console.log(`Proxy for ${this.filename} is handling display request`);
this.loadImage();
this.image.display();
}
}
// 使用示例
function useImage() {
// 创建代理但不实际加载图像
const imageProxy = new ImageProxy('large-image.jpg');
console.log('Image proxy created, but image not loaded yet');
// 当需要显示图像时,才实际加载
console.log('Requesting to display image...');
imageProxy.display();
// 再次显示,不会重新加载
console.log('Displaying image again...');
imageProxy.display();
}
// 2. 保护代理:访问控制
class SecureDocument {
constructor(content, ownerId) {
this.content = content;
this.ownerId = ownerId;
}
read() {
return this.content;
}
update(newContent) {
this.content = newContent;
return true;
}
delete() {
this.content = null;
return true;
}
}
class DocumentAccessProxy {
constructor(document, currentUserId, permissions) {
this.document = document;
this.currentUserId = currentUserId;
this.permissions = permissions;
}
read() {
// 检查读取权限
if (this.permissions.read || this.currentUserId === this.document.ownerId) {
console.log(`User ${this.currentUserId} is reading document owned by ${this.document.ownerId}`);
return this.document.read();
} else {
console.error(`User ${this.currentUserId} does not have permission to read this document`);
throw new Error('Access denied: insufficient permissions');
}
}
update(newContent) {
// 检查更新权限
if (this.permissions.update || this.currentUserId === this.document.ownerId) {
console.log(`User ${this.currentUserId} is updating document owned by ${this.document.ownerId}`);
return this.document.update(newContent);
} else {
console.error(`User ${this.currentUserId} does not have permission to update this document`);
throw new Error('Access denied: insufficient permissions');
}
}
delete() {
// 检查删除权限
if (this.permissions.delete || this.currentUserId === this.document.ownerId) {
console.log(`User ${this.currentUserId} is deleting document owned by ${this.document.ownerId}`);
return this.document.delete();
} else {
console.error(`User ${this.currentUserId} does not have permission to delete this document`);
throw new Error('Access denied: insufficient permissions');
}
}
}
// 使用示例
function manageDocument() {
// 创建文档
const document = new SecureDocument('Confidential information', 1);
// 创建代理:管理员权限
const adminProxy = new DocumentAccessProxy(document, 2, {
read: true,
update: true,
delete: true
});
// 管理员读取和更新文档
console.log(adminProxy.read());
adminProxy.update('Updated confidential information');
console.log(adminProxy.read());
// 创建代理:只读权限
const readOnlyProxy = new DocumentAccessProxy(document, 3, {
read: true,
update: false,
delete: false
});
// 只读用户可以读取但不能更新
console.log(readOnlyProxy.read());
try {
readOnlyProxy.update('This should fail');
} catch (error) {
console.log('Expected error:', error.message);
}
// 文档所有者可以执行所有操作
const ownerProxy = new DocumentAccessProxy(document, 1, {});
console.log(ownerProxy.read());
ownerProxy.update('Owner updated the document');
console.log(ownerProxy.read());
ownerProxy.delete();
console.log('Document deleted by owner');
}
// 3. 缓存代理
class ExpensiveOperation {
constructor() {
this.counter = 0;
}
compute(a, b) {
this.counter++;
console.log(`Computing result for ${a} and ${b} (call #${this.counter})`);
// 模拟耗时计算
for (let i = 0; i < 1000000; i++) {
// 占位计算
}
return a * b;
}
}
class CachedOperationProxy {
constructor(operation) {
this.operation = operation;
this.cache = new Map();
}
// 生成缓存键
getCacheKey(a, b) {
return `${a}:${b}`;
}
// 带缓存的计算方法
compute(a, b) {
const cacheKey = this.getCacheKey(a, b);
// 检查缓存
if (this.cache.has(cacheKey)) {
console.log(`Cache hit for ${a} and ${b}`);
return this.cache.get(cacheKey);
}
// 缓存未命中,执行计算并缓存结果
console.log(`Cache miss for ${a} and ${b}`);
const result = this.operation.compute(a, b);
this.cache.set(cacheKey, result);
return result;
}
// 清除缓存
clearCache() {
console.log('Clearing cache...');
this.cache.clear();
}
// 获取缓存统计信息
getCacheInfo() {
return {
size: this.cache.size,
hits: this.hits || 0,
misses: this.misses || 0
};
}
}
// 使用示例
function useCachedOperation() {
const expensiveOp = new ExpensiveOperation();
const cachedOp = new CachedOperationProxy(expensiveOp);
console.time('First call');
const result1 = cachedOp.compute(1234, 5678);
console.timeEnd('First call');
console.time('Second call (same parameters)');
const result2 = cachedOp.compute(1234, 5678);
console.timeEnd('Second call (same parameters)');
console.time('Third call (different parameters)');
const result3 = cachedOp.compute(5678, 1234);
console.timeEnd('Third call (different parameters)');
console.log('Cache info:', cachedOp.getCacheInfo());
// 清除缓存后再次调用
cachedOp.clearCache();
console.time('Fourth call (after cache clear)');
const result4 = cachedOp.compute(1234, 5678);
console.timeEnd('Fourth call (after cache clear)');
}
// 4. ES6 Proxy实现
function createLoggingProxy(target) {
return new Proxy(target, {
get(target, property, receiver) {
console.log(`Getting property: ${property}`);
const value = Reflect.get(target, property, receiver);
// 如果获取的是函数,返回一个包装函数以记录调用
if (typeof value === 'function') {
return function(...args) {
console.log(`Calling method: ${property} with args:`, args);
const result = value.apply(this === receiver ? target : this, args);
console.log(`Method ${property} returned:`, result);
return result;
};
}
return value;
},
set(target, property, value, receiver) {
console.log(`Setting property: ${property} to value:`, value);
return Reflect.set(target, property, value, receiver);
},
deleteProperty(target, property) {
console.log(`Deleting property: ${property}`);
return Reflect.deleteProperty(target, property);
}
});
}
// 使用ES6 Proxy示例
function useEs6Proxy() {
const user = {
name: 'John Doe',
age: 30,
greet() {
return `Hello, my name is ${this.name}`;
},
birthday() {
this.age++;
return `Happy Birthday! Now I'm ${this.age} years old`;
}
};
const proxiedUser = createLoggingProxy(user);
// 访问属性
console.log(proxiedUser.name);
// 修改属性
proxiedUser.age = 31;
// 调用方法
console.log(proxiedUser.greet());
console.log(proxiedUser.birthday());
// 删除属性
delete proxiedUser.age;
// 添加新属性
proxiedUser.email = 'john@example.com';
}
2.4 组合模式
组合模式将对象组合成树形结构来表示"部分-整体"的层次结构,使得客户端可以统一地处理单个对象和对象组合。
// 1. 基本组合模式
class Component {
constructor(name) {
this.name = name;
}
add(component) { throw new Error('Method not implemented'); }
remove(component) { throw new Error('Method not implemented'); }
getChild(index) { throw new Error('Method not implemented'); }
display(indent = 0) { throw new Error('Method not implemented'); }
getSize() { throw new Error('Method not implemented'); }
}
// 叶节点:文件
class File extends Component {
constructor(name, size) {
super(name);
this.size = size;
}
// 叶节点不支持添加子节点
add(component) { console.log('Cannot add to a file'); }
remove(component) { console.log('Cannot remove from a file'); }
getChild(index) { return null; }
display(indent = 0) {
console.log(' '.repeat(indent) + `- ${this.name} (${this.size}KB)`);
}
getSize() {
return this.size;
}
}
// 组合节点:目录
class Directory extends Component {
constructor(name) {
super(name);
this.children = [];
}
add(component) {
this.children.push(component);
return this; // 支持链式调用
}
remove(component) {
const index = this.children.indexOf(component);
if (index !== -1) {
this.children.splice(index, 1);
}
}
getChild(index) {
return this.children[index] || null;
}
display(indent = 0) {
console.log(' '.repeat(indent) + `+ ${this.name}`);
for (const child of this.children) {
child.display(indent + 2);
}
}
getSize() {
return this.children.reduce((total, child) => total + child.getSize(), 0);
}
// 递归查找文件
findFile(filename) {
for (const child of this.children) {
if (child instanceof File && child.name === filename) {
return child;
} else if (child instanceof Directory) {
const found = child.findFile(filename);
if (found) return found;
}
}
return null;
}
// 统计文件类型
countFileTypes() {
const counts = {};
for (const child of this.children) {
if (child instanceof File) {
const extension = child.name.split('.').pop() || 'no-extension';
counts[extension] = (counts[extension] || 0) + 1;
} else if (child instanceof Directory) {
const childCounts = child.countFileTypes();
// 合并统计结果
for (const [type, count] of Object.entries(childCounts)) {
counts[type] = (counts[type] || 0) + count;
}
}
}
return counts;
}
}
// 使用示例
function createFileSystem() {
// 创建根目录
const root = new Directory('root');
// 创建子目录
const docs = new Directory('documents');
const images = new Directory('images');
const code = new Directory('code');
// 创建文件
const readme = new File('README.md', 1);
const resume = new File('resume.pdf', 500);
const profile = new File('profile.jpg', 2048);
const logo = new File('logo.png', 1024);
const app = new File('app.js', 10);
const config = new File('config.json', 2);
const index = new File('index.html', 5);
// 构建文件系统结构
root.add(readme);
root.add(docs);
root.add(images);
root.add(code);
docs.add(resume);
images.add(profile);
images.add(logo);
code.add(app);
code.add(config);
code.add(index);
// 显示文件系统结构
console.log('File system structure:');
root.display();
// 计算总大小
console.log(`\nTotal size: ${root.getSize()}KB`);
// 查找文件
const foundFile = root.findFile('app.js');
console.log(`\nFound file: ${foundFile ? foundFile.name : 'Not found'}`);
// 统计文件类型
const fileTypes = root.countFileTypes();
console.log('\nFile type counts:', fileTypes);
}
// 2. 组合模式在UI组件中的应用
class UIComponent {
constructor(name) {
this.name = name;
this.props = {};
this.children = [];
}
setProp(key, value) {
this.props[key] = value;
return this;
}
add(child) {
this.children.push(child);
return this;
}
render() {
throw new Error('Method not implemented');
}
}
// 叶节点:基本UI元素
class UIElem extends UIComponent {
constructor(name, tagName = 'div') {
super(name);
this.tagName = tagName;
}
render(indent = 0) {
const indentStr = ' '.repeat(indent);
const propsStr = Object.entries(this.props)
.map(([key, value]) => ` ${key}="${value}"`)
.join('');
if (this.children.length === 0) {
return `${indentStr}<${this.tagName}${propsStr}>${this.name}</${this.tagName}>`;
}
let result = `${indentStr}<${this.tagName}${propsStr}>
`;
for (const child of this.children) {
result += child.render(indent + 2) + '\n';
}
result += `${indentStr}</${this.tagName}>`;
return result;
}
}
// 组合节点:容器组件
class UIContainer extends UIComponent {
constructor(name, layout = 'flex') {
super(name);
this.layout = layout;
}
render(indent = 0) {
const indentStr = ' '.repeat(indent);
const props = { ...this.props };
// 设置默认布局样式
if (this.layout) {
props.style = props.style || '';
if (this.layout === 'flex') {
props.style += 'display: flex; ';
} else if (this.layout === 'grid') {
props.style += 'display: grid; ';
}
}
const propsStr = Object.entries(props)
.map(([key, value]) => ` ${key}="${value}"`)
.join('');
let result = `${indentStr}<div class="container"${propsStr}>
`;
result += `${indentStr} <!-- ${this.name} -->
`;
for (const child of this.children) {
result += child.render(indent + 2) + '\n';
}
result += `${indentStr}</div>`;
return result;
}
}
// 使用示例
function createUI() {
// 创建页面容器
const page = new UIContainer('My App Page')
.setProp('id', 'app')
.setProp('style', 'max-width: 1200px; margin: 0 auto;');
// 创建页眉
const header = new UIContainer('Header', 'flex')
.setProp('id', 'header')
.setProp('style', 'justify-content: space-between; align-items: center; padding: 20px; background-color: #333; color: white;');
header.add(new UIElem('My App', 'h1')
.setProp('style', 'margin: 0; font-size: 24px;'));
header.add(new UIElem('Login', 'button')
.setProp('class', 'btn btn-primary')
.setProp('style', 'background-color: #007bff; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer;'));
// 创建主内容区
const main = new UIContainer('Main Content', 'flex')
.setProp('id', 'main')
.setProp('style', 'gap: 20px; padding: 20px;');
// 创建侧边栏
const sidebar = new UIContainer('Sidebar')
.setProp('id', 'sidebar')
.setProp('style', 'width: 250px; background-color: #f8f9fa; padding: 20px; border-radius: 8px;');
sidebar.add(new UIElem('Navigation', 'h2')
.setProp('style', 'margin-top: 0; font-size: 18px;'));
const navList = new UIContainer('Nav List')
.setProp('class', 'nav-list');
navList.add(new UIElem('Home', 'a')
.setProp('href', '#home')
.setProp('style', 'display: block; padding: 10px; color: #333; text-decoration: none;'));
navList.add(new UIElem('Products', 'a')
.setProp('href', '#products')
.setProp('style', 'display: block; padding: 10px; color: #333; text-decoration: none;'));
navList.add(new UIElem('About', 'a')
.setProp('href', '#about')
.setProp('style', 'display: block; padding: 10px; color: #333; text-decoration: none;'));
sidebar.add(navList);
// 创建内容区
const content = new UIContainer('Content Area')
.setProp('id', 'content')
.setProp('style', 'flex: 1;');
content.add(new UIElem('Welcome to My App', 'h2')
.setProp('style', 'margin-top: 0;'));
content.add(new UIElem('This is a demo of the Composite pattern in UI components.', 'p'));
// 创建卡片网格
const cardGrid = new UIContainer('Card Grid', 'grid')
.setProp('style', 'grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; margin-top: 20px;');
// 添加卡片
for (let i = 1; i <= 4; i++) {
const card = new UIContainer(`Card ${i}`)
.setProp('class', 'card')
.setProp('style', 'border: 1px solid #ddd; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);');
card.add(new UIElem(`Card Title ${i}`, 'h3')
.setProp('style', 'margin-top: 0;'));
card.add(new UIElem(`This is the content of card ${i}.`, 'p'));
card.add(new UIElem('Learn More', 'a')
.setProp('href', `#card-${i}`)
.setProp('class', 'btn')
.setProp('style', 'color: #007bff; text-decoration: none;'));
cardGrid.add(card);
}
content.add(cardGrid);
// 组装主内容区
main.add(sidebar);
main.add(content);
// 创建页脚
const footer = new UIContainer('Footer')
.setProp('id', 'footer')
.setProp('style', 'text-align: center; padding: 20px; background-color: #333; color: white; margin-top: 20px;');
footer.add(new UIElem('© 2023 My App. All rights reserved.', 'p')
.setProp('style', 'margin: 0;'));
// 组装页面
page.add(header);
page.add(main);
page.add(footer);
// 渲染整个UI
console.log(page.render());
}
// 3. 组合模式在事件处理中的应用
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) {
if (!this.events.has(event)) return this;
const listeners = this.events.get(event);
const index = listeners.indexOf(listener);
if (index !== -1) {
listeners.splice(index, 1);
}
return this;
}
emit(event, ...args) {
if (!this.events.has(event)) return false;
const listeners = this.events.get(event);
for (const listener of listeners) {
try {
listener.apply(this, args);
} catch (error) {
console.error(`Error in event listener for ${event}:`, error);
}
}
return true;
}
}
// 组合式事件发射器
class CompositeEventEmitter extends EventEmitter {
constructor() {
super();
this.children = [];
}
add(child) {
this.children.push(child);
return this;
}
remove(child) {
const index = this.children.indexOf(child);
if (index !== -1) {
this.children.splice(index, 1);
}
return this;
}
// 覆盖emit方法,使其也触发子组件的事件
emit(event, ...args) {
// 先触发自己的事件
const result = super.emit(event, ...args);
// 然后触发所有子组件的同名事件
for (const child of this.children) {
try {
if (typeof child.emit === 'function') {
child.emit(event, ...args);
}
} catch (error) {
console.error(`Error emitting event in child component:`, error);
}
}
return result;
}
// 向所有子组件广播消息
broadcast(event, ...args) {
for (const child of this.children) {
try {
if (typeof child.emit === 'function') {
child.emit(event, ...args);
}
} catch (error) {
console.error(`Error broadcasting to child component:`, error);
}
}
}
}
// 使用示例
function useCompositeEventEmitter() {
// 创建主事件发射器
const appEvents = new CompositeEventEmitter();
// 创建子事件发射器
const userEvents = new EventEmitter();
const productEvents = new EventEmitter();
const orderEvents = new EventEmitter();
// 添加子事件发射器到主发射器
appEvents.add(userEvents);
appEvents.add(productEvents);
appEvents.add(orderEvents);
// 为主发射器添加监听器
appEvents.on('app_started', () => {
console.log('Main app started');
});
// 为子发射器添加监听器
userEvents.on('user_created', (user) => {
console.log(`User created: ${user.name}`);
});
productEvents.on('product_updated', (product) => {
console.log(`Product updated: ${product.name}`);
});
orderEvents.on('order_placed', (order) => {
console.log(`Order placed: #${order.id}`);
});
// 添加全局事件监听器(会被所有子组件接收)
userEvents.on('global_notification', (message) => {
console.log(`User module received: ${message}`);
});
productEvents.on('global_notification', (message) => {
console.log(`Product module received: ${message}`);
});
// 触发主事件
console.log('Triggering app_started event:');
appEvents.emit('app_started');
// 触发特定子组件事件
console.log('\nTriggering user_created event:');
userEvents.emit('user_created', { id: 1, name: 'John Doe' });
// 触发全局事件
console.log('\nTriggering global_notification event:');
appEvents.emit('global_notification', 'System maintenance at 23:00');
// 使用broadcast方法
console.log('\nBroadcasting maintenance message:');
appEvents.broadcast('maintenance_scheduled', {
time: '23:00',
duration: '2 hours'
});
}
2.5 桥接模式
桥接模式将抽象部分与实现部分分离,使它们都可以独立地变化。这在处理多维度变化的场景时特别有用。
// 1. 基本桥接模式
// 实现部分接口
class Color {
applyColor() { throw new Error('Method not implemented'); }
}
// 具体实现:红色
class RedColor extends Color {
applyColor() {
return 'red';
}
}
// 具体实现:绿色
class GreenColor extends Color {
applyColor() {
return 'green';
}
}
// 具体实现:蓝色
class BlueColor extends Color {
applyColor() {
return 'blue';
}
}
// 抽象部分
class Shape {
constructor(color) {
this.color = color;
}
// 设置颜色(运行时切换实现)
setColor(color) {
this.color = color;
}
draw() { throw new Error('Method not implemented'); }
}
// 扩展抽象部分:圆形
class Circle extends Shape {
constructor(color, radius = 1) {
super(color);
this.radius = radius;
}
draw() {
return `Drawing a ${this.color.applyColor()} circle with radius ${this.radius}`;
}
}
// 扩展抽象部分:矩形
class Rectangle extends Shape {
constructor(color, width = 1, height = 1) {
super(color);
this.width = width;
this.height = height;
}
draw() {
return `Drawing a ${this.color.applyColor()} rectangle with width ${this.width} and height ${this.height}`;
}
}
// 扩展抽象部分:三角形
class Triangle extends Shape {
constructor(color, base = 1, height = 1) {
super(color);
this.base = base;
this.height = height;
}
draw() {
return `Drawing a ${this.color.applyColor()} triangle with base ${this.base} and height ${this.height}`;
}
}
// 使用示例
function useBridgePattern() {
// 创建颜色实现
const red = new RedColor();
const green = new GreenColor();
const blue = new BlueColor();
// 创建形状并设置颜色(桥接)
const redCircle = new Circle(red, 5);
const greenRectangle = new Rectangle(green, 4, 6);
const blueTriangle = new Triangle(blue, 3, 8);
// 绘制形状
console.log(redCircle.draw()); // Drawing a red circle with radius 5
console.log(greenRectangle.draw()); // Drawing a green rectangle with width 4 and height 6
console.log(blueTriangle.draw()); // Drawing a blue triangle with base 3 and height 8
// 运行时切换颜色
redCircle.setColor(blue);
console.log(redCircle.draw()); // Drawing a blue circle with radius 5
greenRectangle.setColor(red);
console.log(greenRectangle.draw()); // Drawing a red rectangle with width 4 and height 6
}
// 2. 桥接模式在支付系统中的应用
// 支付方式实现接口
class PaymentMethod {
pay(amount) { throw new Error('Method not implemented'); }
getPaymentDetails() { throw new Error('Method not implemented'); }
}
// 具体实现:信用卡支付
class CreditCardPayment extends PaymentMethod {
constructor(cardNumber, cardHolder, expiryDate, cvv) {
super();
this.cardNumber = cardNumber;
this.cardHolder = cardHolder;
this.expiryDate = expiryDate;
this.cvv = cvv;
}
pay(amount) {
console.log(`Processing credit card payment of $${amount}`);
console.log(`Card number: ****-****-****-${this.cardNumber.slice(-4)}`);
return { success: true, transactionId: `cc_${Date.now()}` };
}
getPaymentDetails() {
return {
type: 'Credit Card',
cardHolder: this.cardHolder,
lastFourDigits: this.cardNumber.slice(-4)
};
}
}
// 具体实现:PayPal支付
class PayPalPayment extends PaymentMethod {
constructor(email) {
super();
this.email = email;
}
pay(amount) {
console.log(`Processing PayPal payment of $${amount}`);
console.log(`PayPal email: ${this.email}`);
return { success: true, transactionId: `pp_${Date.now()}` };
}
getPaymentDetails() {
return {
type: 'PayPal',
email: this.email
};
}
}
// 具体实现:加密货币支付
class CryptoPayment extends PaymentMethod {
constructor(cryptoType, walletAddress) {
super();
this.cryptoType = cryptoType;
this.walletAddress = walletAddress;
}
pay(amount) {
console.log(`Processing ${this.cryptoType} payment of $${amount} equivalent`);
console.log(`Wallet address: ${this.walletAddress.slice(0, 6)}...${this.walletAddress.slice(-6)}`);
return { success: true, transactionId: `crypto_${Date.now()}` };
}
getPaymentDetails() {
return {
type: this.cryptoType,
walletAddress: this.walletAddress
};
}
}
// 抽象部分:订单
class Order {
constructor(orderId, items, paymentMethod) {
this.orderId = orderId;
this.items = items;
this.paymentMethod = paymentMethod;
}
// 设置支付方式(运行时切换实现)
setPaymentMethod(paymentMethod) {
this.paymentMethod = paymentMethod;
}
// 计算订单总额
calculateTotal() {
return this.items.reduce((total, item) => total + (item.price * item.quantity), 0);
}
// 处理支付
processPayment() {
const total = this.calculateTotal();
console.log(`Processing payment for Order #${this.orderId}`);
console.log(`Order items: ${this.items.length}`);
console.log(`Total amount: $${total.toFixed(2)}`);
const paymentResult = this.paymentMethod.pay(total);
if (paymentResult.success) {
console.log(`Payment successful! Transaction ID: ${paymentResult.transactionId}`);
console.log('Payment details:', this.paymentMethod.getPaymentDetails());
} else {
console.log('Payment failed!');
}
return paymentResult;
}
}
// 扩展抽象部分:在线订单
class OnlineOrder extends Order {
constructor(orderId, items, paymentMethod, shippingAddress) {
super(orderId, items, paymentMethod);
this.shippingAddress = shippingAddress;
this.isExpressShipping = false;
}
setExpressShipping(express) {
this.isExpressShipping = express;
}
calculateTotal() {
let total = super.calculateTotal();
// 添加运费
total += this.isExpressShipping ? 15 : 5;
return total;
}
processPayment() {
console.log('Processing online order with shipping');
console.log('Shipping to:', this.shippingAddress);
console.log('Express shipping:', this.isExpressShipping);
return super.processPayment();
}
}
// 扩展抽象部分:数字产品订单
class DigitalProductOrder extends Order {
constructor(orderId, items, paymentMethod, email) {
super(orderId, items, paymentMethod);
this.deliveryEmail = email;
}
calculateTotal() {
// 数字产品没有运费,但可能有税费
const subtotal = super.calculateTotal();
return subtotal * 1.08; // 8% tax
}
processPayment() {
const result = super.processPayment();
if (result.success) {
console.log(`Digital products will be delivered to: ${this.deliveryEmail}`);
// 这里会发送下载链接等
}
return result;
}
}
// 使用示例
function processOrders() {
// 创建支付方式
const creditCard = new CreditCardPayment('1234567890123456', 'John Doe', '12/25', '123');
const payPal = new PayPalPayment('john.doe@example.com');
const crypto = new CryptoPayment('Bitcoin', '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa');
// 创建订单项
const items1 = [
{ id: 1, name: 'Laptop', price: 999.99, quantity: 1 },
{ id: 2, name: 'Mouse', price: 24.99, quantity: 2 }
];
const items2 = [
{ id: 3, name: 'E-book', price: 19.99, quantity: 1 },
{ id: 4, name: 'Online Course', price: 149.99, quantity: 1 }
];
// 创建在线订单
const onlineOrder = new OnlineOrder('ORD-001', items1, creditCard, {
name: 'John Doe',
address: '123 Main St',
city: 'New York',
zip: '10001',
country: 'USA'
});
onlineOrder.setExpressShipping(true);
console.log('\nProcessing online order with credit card:');
onlineOrder.processPayment();
// 切换支付方式
console.log('\nSwitching to PayPal for the same order:');
onlineOrder.setPaymentMethod(payPal);
onlineOrder.processPayment();
// 创建数字产品订单
const digitalOrder = new DigitalProductOrder('ORD-002', items2, crypto, 'john.doe@example.com');
console.log('\nProcessing digital product order with cryptocurrency:');
digitalOrder.processPayment();
}
// 3. 桥接模式在日志系统中的应用
// 日志输出实现接口
class LogOutput {
log(level, message) { throw new Error('Method not implemented'); }
setFormatter(formatter) { throw new Error('Method not implemented'); }
}
// 具体实现:控制台输出
class ConsoleOutput extends LogOutput {
constructor() {
super();
this.formatter = null;
}
setFormatter(formatter) {
this.formatter = formatter;
}
log(level, message) {
const formattedMessage = this.formatter ? this.formatter.format(level, message) : `${level}: ${message}`;
switch (level.toLowerCase()) {
case 'error':
console.error(formattedMessage);
break;
case 'warn':
console.warn(formattedMessage);
break;
case 'info':
console.info(formattedMessage);
break;
case 'debug':
console.debug(formattedMessage);
break;
default:
console.log(formattedMessage);
}
}
}
// 具体实现:文件输出
class FileOutput extends LogOutput {
constructor(filePath) {
super();
this.filePath = filePath;
this.formatter = null;
console.log(`Logging to file: ${filePath}`);
}
setFormatter(formatter) {
this.formatter = formatter;
}
log(level, message) {
const formattedMessage = this.formatter ? this.formatter.format(level, message) : `${level}: ${message}`;
// 实际应用中,这里会写入文件
console.log(`[File: ${this.filePath}] ${formattedMessage}`);
}
}
// 具体实现:网络输出(发送到远程服务器)
class NetworkOutput extends LogOutput {
constructor(endpoint, apiKey = null) {
super();
this.endpoint = endpoint;
this.apiKey = apiKey;
this.formatter = null;
}
setFormatter(formatter) {
this.formatter = formatter;
}
log(level, message) {
const formattedMessage = this.formatter ? this.formatter.format(level, message) : `${level}: ${message}`;
// 模拟网络请求
console.log(`[Network: ${this.endpoint}] Sending log message`);
if (this.apiKey) {
console.log(` API Key: ${this.apiKey}`);
}
console.log(` Message: ${formattedMessage}`);
}
}
// 日志格式化器
class LogFormatter {
format(level, message) { throw new Error('Method not implemented'); }
}
// 简单格式化器
class SimpleFormatter extends LogFormatter {
format(level, message) {
return `[${level.toUpperCase()}] ${message}`;
}
}
// 时间戳格式化器
class TimestampFormatter extends LogFormatter {
format(level, message) {
const timestamp = new Date().toISOString();
return `[${timestamp}] [${level.toUpperCase()}] ${message}`;
}
}
// JSON格式化器
class JSONFormatter extends LogFormatter {
format(level, message) {
const logEntry = {
timestamp: new Date().toISOString(),
level: level.toUpperCase(),
message: message
};
return JSON.stringify(logEntry);
}
}
// 抽象部分:日志记录器
class Logger {
constructor(output) {
this.output = output;
this.level = 'info'; // 默认日志级别
}
// 设置输出方式(运行时切换实现)
setOutput(output) {
this.output = output;
}
// 设置日志级别
setLevel(level) {
this.level = level.toLowerCase();
}
// 检查是否应该记录此级别
shouldLog(level) {
const levels = ['debug', 'info', 'warn', 'error'];
return levels.indexOf(level.toLowerCase()) >= levels.indexOf(this.level);
}
// 日志方法
debug(message) {
if (this.shouldLog('debug')) {
this.output.log('debug', message);
}
}
info(message) {
if (this.shouldLog('info')) {
this.output.log('info', message);
}
}
warn(message) {
if (this.shouldLog('warn')) {
this.output.log('warn', message);
}
}
error(message) {
if (this.shouldLog('error')) {
this.output.log('error', message);
}
}
}
// 扩展抽象部分:应用日志记录器
class AppLogger extends Logger {
constructor(output, appName) {
super(output);
this.appName = appName;
}
// 重写日志方法,添加应用名称
debug(message) {
if (this.shouldLog('debug')) {
this.output.log('debug', `[${this.appName}] ${message}`);
}
}
info(message) {
if (this.shouldLog('info')) {
this.output.log('info', `[${this.appName}] ${message}`);
}
}
warn(message) {
if (this.shouldLog('warn')) {
this.output.log('warn', `[${this.appName}] ${message}`);
}
}
error(message) {
if (this.shouldLog('error')) {
this.output.log('error', `[${this.appName}] ${message}`);
}
}
// 记录请求信息
logRequest(req) {
this.info(`Request: ${req.method} ${req.url} from ${req.ip}`);
}
// 记录错误信息
logError(error, context = {}) {
const contextStr = Object.keys(context).length > 0 ? ` Context: ${JSON.stringify(context)}` : '';
this.error(`${error.message}${contextStr}\n${error.stack}`);
}
}
// 扩展抽象部分:业务日志记录器
class BusinessLogger extends Logger {
constructor(output, businessDomain) {
super(output);
this.businessDomain = businessDomain;
}
// 记录业务事件
logEvent(eventName, eventData = {}) {
const eventInfo = {
domain: this.businessDomain,
event: eventName,
data: eventData
};
this.info(`Business event: ${JSON.stringify(eventInfo)}`);
}
// 记录业务指标
logMetric(metricName, value, tags = {}) {
const metricInfo = {
domain: this.businessDomain,
metric: metricName,
value: value,
tags: tags
};
this.info(`Business metric: ${JSON.stringify(metricInfo)}`);
}
}
// 使用示例
function useLoggerBridge() {
// 创建输出实现
const consoleOutput = new ConsoleOutput();
const fileOutput = new FileOutput('app.log');
const networkOutput = new NetworkOutput('https://logs.example.com/api', 'api-key-123');
// 创建格式化器
const simpleFormatter = new SimpleFormatter();
const timestampFormatter = new TimestampFormatter();
const jsonFormatter = new JSONFormatter();
// 设置格式化器
consoleOutput.setFormatter(timestampFormatter);
fileOutput.setFormatter(jsonFormatter);
networkOutput.setFormatter(jsonFormatter);
// 创建应用日志记录器
const appLogger = new AppLogger(consoleOutput, 'MyApp');
appLogger.setLevel('debug');
// 记录日志
appLogger.debug('Application starting...');
appLogger.info('Application started successfully');
appLogger.warn('Configuration file not found, using defaults');
appLogger.error(new Error('Failed to connect to database'));
// 切换输出方式
console.log('\nSwitching to file output:');
appLogger.setOutput(fileOutput);
appLogger.info('This message goes to the file');
console.log('\nSwitching to network output:');
appLogger.setOutput(networkOutput);
appLogger.info('This message is sent to the network');
// 创建业务日志记录器
const orderLogger = new BusinessLogger(consoleOutput, 'orders');
orderLogger.logEvent('order_created', { orderId: 'ORD-001', amount: 199.99 });
orderLogger.logMetric('order_count', 150, { day: 'monday', region: 'north' });
// 模拟HTTP请求日志
const mockRequest = {
method: 'POST',
url: '/api/users',
ip: '192.168.1.1'
};
appLogger.logRequest(mockRequest);
// 模拟错误日志
try {
throw new Error('Invalid user data');
} catch (error) {
appLogger.logError(error, { userId: 123, operation: 'update_profile' });
}
}
### 2.6 外观模式
外观模式提供了一个统一的接口,用来访问子系统中的一组接口。外观模式定义了一个高层接口,让子系统更容易使用。
```javascript
// 1. 基本外观模式
// 子系统组件1:CPU
class CPU {
start() {
console.log('CPU starting...');
}
execute() {
console.log('CPU executing instructions...');
}
stop() {
console.log('CPU stopping...');
}
}
// 子系统组件2:内存
class Memory {
load(position, data) {
console.log(`Memory loading data at position ${position}: ${data}`);
}
read(position) {
console.log(`Memory reading data from position ${position}`);
return `Data from ${position}`;
}
clear() {
console.log('Memory clearing...');
}
}
// 子系统组件3:硬盘
class HardDrive {
read(sector, size) {
console.log(`HardDrive reading ${size} bytes from sector ${sector}`);
return `Data from sector ${sector}`;
}
write(sector, data) {
console.log(`HardDrive writing data to sector ${sector}: ${data}`);
}
spinUp() {
console.log('HardDrive spinning up...');
}
spinDown() {
console.log('HardDrive spinning down...');
}
}
// 子系统组件4:操作系统
class OperatingSystem {
boot() {
console.log('OperatingSystem booting...');
}
loadKernel() {
console.log('OperatingSystem loading kernel...');
}
shutdown() {
console.log('OperatingSystem shutting down...');
}
}
// 外观类:计算机
class Computer {
constructor() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
this.os = new OperatingSystem();
}
// 简化的启动接口
start() {
console.log('Computer starting process initiated...');
this.hardDrive.spinUp();
this.os.loadKernel();
this.memory.load(0, 'Bootstrap code');
this.cpu.start();
this.cpu.execute();
this.os.boot();
console.log('Computer started successfully!');
}
// 简化的关闭接口
shutdown() {
console.log('Computer shutdown process initiated...');
this.os.shutdown();
this.cpu.stop();
this.memory.clear();
this.hardDrive.spinDown();
console.log('Computer shut down successfully!');
}
// 简化的数据读取接口
readData(sector) {
console.log(`Reading data from sector ${sector}...`);
const data = this.hardDrive.read(sector, 512);
this.memory.load(100, data);
return this.memory.read(100);
}
}
// 使用示例
function useComputer() {
const computer = new Computer();
// 客户端只需与外观交互,而不需要了解子系统的复杂细节
computer.start();
// 读取数据
const data = computer.readData(42);
console.log('Read result:', data);
// 关闭计算机
computer.shutdown();
}
// 2. 外观模式在API网关中的应用
// 子系统组件1:用户服务
class UserService {
async getUserById(id) {
console.log(`UserService: Getting user with id ${id}`);
// 模拟API调用
return { id, name: `User ${id}`, email: `user${id}@example.com` };
}
async updateUser(id, data) {
console.log(`UserService: Updating user ${id} with data`, data);
return { id, ...data };
}
}
// 子系统组件2:订单服务
class OrderService {
async getOrdersByUser(userId) {
console.log(`OrderService: Getting orders for user ${userId}`);
// 模拟API调用
return [
{ id: 1, userId, product: 'Product A', amount: 99.99 },
{ id: 2, userId, product: 'Product B', amount: 49.99 }
];
}
async createOrder(orderData) {
console.log(`OrderService: Creating order with data`, orderData);
return { id: Date.now(), ...orderData };
}
}
// 子系统组件3:支付服务
class PaymentService {
async processPayment(orderId, amount, paymentMethod) {
console.log(`PaymentService: Processing payment of $${amount} for order ${orderId} using ${paymentMethod}`);
return { success: true, transactionId: `txn_${Date.now()}` };
}
async getPaymentHistory(userId) {
console.log(`PaymentService: Getting payment history for user ${userId}`);
return [
{ id: 'txn_1', orderId: 1, amount: 99.99, status: 'completed' },
{ id: 'txn_2', orderId: 2, amount: 49.99, status: 'completed' }
];
}
}
// 子系统组件4:通知服务
class NotificationService {
async sendEmail(to, subject, body) {
console.log(`NotificationService: Sending email to ${to} with subject "${subject}"`);
return { success: true, messageId: `email_${Date.now()}` };
}
async sendSMS(to, message) {
console.log(`NotificationService: Sending SMS to ${to} with message "${message}"`);
return { success: true, messageId: `sms_${Date.now()}` };
}
}
// 外观类:API网关
class ApiGateway {
constructor() {
this.userService = new UserService();
this.orderService = new OrderService();
this.paymentService = new PaymentService();
this.notificationService = new NotificationService();
}
// 用户详情与订单的组合接口
async getUserWithOrders(userId) {
try {
// 并行调用多个服务
const [user, orders, payments] = await Promise.all([
this.userService.getUserById(userId),
this.orderService.getOrdersByUser(userId),
this.paymentService.getPaymentHistory(userId)
]);
// 组合结果
return {
user,
orders,
payments,
totalOrders: orders.length,
totalSpent: orders.reduce((total, order) => total + order.amount, 0)
};
} catch (error) {
console.error('Error getting user with orders:', error);
throw new Error('Failed to fetch user data');
}
}
// 完整的订单创建流程接口
async createOrderWithPayment(userId, orderData, paymentMethod) {
try {
// 1. 验证用户
const user = await this.userService.getUserById(userId);
if (!user) {
throw new Error('User not found');
}
// 2. 创建订单
const order = await this.orderService.createOrder({
userId,
...orderData
});
// 3. 处理支付
const paymentResult = await this.paymentService.processPayment(
order.id,
order.amount,
paymentMethod
);
if (!paymentResult.success) {
throw new Error('Payment failed');
}
// 4. 发送通知
await this.notificationService.sendEmail(
user.email,
'Order Confirmation',
`Your order #${order.id} has been placed successfully.`
);
// 返回组合结果
return {
success: true,
order,
payment: paymentResult,
message: 'Order placed successfully'
};
} catch (error) {
console.error('Error creating order with payment:', error);
// 尝试发送失败通知
try {
const user = await this.userService.getUserById(userId);
if (user) {
await this.notificationService.sendEmail(
user.email,
'Order Failed',
`We were unable to process your order. Please try again.`
);
}
} catch (notifyError) {
console.error('Failed to send notification:', notifyError);
}
throw error;
}
}
// 用户更新与通知的组合接口
async updateUserProfile(userId, userData) {
try {
// 更新用户
const updatedUser = await this.userService.updateUser(userId, userData);
// 发送更新通知
await this.notificationService.sendEmail(
updatedUser.email,
'Profile Updated',
'Your profile has been updated successfully.'
);
return {
success: true,
user: updatedUser,
message: 'Profile updated successfully'
};
} catch (error) {
console.error('Error updating user profile:', error);
throw new Error('Failed to update profile');
}
}
}
// 使用示例
async function useApiGateway() {
const apiGateway = new ApiGateway();
// 获取用户及其订单和支付历史
console.log('\nGetting user with orders:');
const userData = await apiGateway.getUserWithOrders(1);
console.log('User data with orders:', userData);
// 创建订单并处理支付
console.log('\nCreating order with payment:');
const orderResult = await apiGateway.createOrderWithPayment(
1,
{ product: 'New Laptop', amount: 1299.99, quantity: 1 },
'credit_card'
);
console.log('Order result:', orderResult);
// 更新用户资料
console.log('\nUpdating user profile:');
const updateResult = await apiGateway.updateUserProfile(
1,
{ name: 'Updated User Name', email: 'updated@example.com' }
);
console.log('Update result:', updateResult);
}
// 3. 外观模式在数据处理管道中的应用
// 子系统组件1:数据提取器
class DataExtractor {
extract(source) {
console.log(`DataExtractor: Extracting data from ${source}`);
// 模拟数据提取
return [
{ id: 1, name: 'Item 1', value: 100 },
{ id: 2, name: 'Item 2', value: 200 },
{ id: 3, name: 'Item 3', value: 300 }
];
}
extractFromAPI(endpoint) {
console.log(`DataExtractor: Extracting data from API endpoint ${endpoint}`);
// 模拟API数据提取
return [
{ id: 4, name: 'API Item 1', value: 400 },
{ id: 5, name: 'API Item 2', value: 500 }
];
}
}
// 子系统组件2:数据转换器
class DataTransformer {
transform(data, transformation) {
console.log(`DataTransformer: Applying transformation ${transformation} to ${data.length} items`);
switch (transformation) {
case 'normalize':
return data.map(item => ({
...item,
normalizedValue: item.value / 100
}));
case 'filter':
return data.filter(item => item.value > 200);
case 'aggregate':
return {
count: data.length,
sum: data.reduce((sum, item) => sum + item.value, 0),
average: data.reduce((sum, item) => sum + item.value, 0) / data.length
};
default:
return data;
}
}
format(data, format) {
console.log(`DataTransformer: Formatting data to ${format}`);
if (format === 'json') {
return JSON.stringify(data, null, 2);
} else if (format === 'csv') {
if (!data || data.length === 0) return '';
const headers = Object.keys(data[0]);
const csvHeaders = headers.join(',');
const csvRows = data.map(row =>
headers.map(header => `"${row[header]}"`).join(',')
);
return [csvHeaders, ...csvRows].join('\n');
}
return data;
}
}
// 子系统组件3:数据加载器
class DataLoader {
load(data, destination) {
console.log(`DataLoader: Loading ${typeof data === 'string' ? 'formatted' : 'transformed'} data to ${destination}`);
// 模拟数据加载
console.log(`Successfully loaded data to ${destination}`);
return { success: true, records: Array.isArray(data) ? data.length : 1 };
}
saveToFile(data, filePath) {
console.log(`DataLoader: Saving data to file ${filePath}`);
// 模拟文件保存
console.log(`File saved: ${filePath}`);
console.log('File content preview:', typeof data === 'string' ? data.substring(0, 50) + '...' : data);
return { success: true, filePath };
}
}
// 外观类:ETL(提取、转换、加载)管道
class ETLPipeline {
constructor() {
this.extractor = new DataExtractor();
this.transformer = new DataTransformer();
this.loader = new DataLoader();
}
// 简单的数据处理流程
async processData(source, destination) {
try {
console.log(`Starting ETL process from ${source} to ${destination}...`);
// 1. 提取数据
const rawData = this.extractor.extract(source);
// 2. 转换数据
const transformedData = this.transformer.transform(rawData, 'normalize');
// 3. 加载数据
const loadResult = this.loader.load(transformedData, destination);
console.log('ETL process completed successfully!');
return loadResult;
} catch (error) {
console.error('ETL process failed:', error);
throw new Error('Data processing failed');
}
}
// 高级数据处理流程:API数据到CSV文件
async apiToCsvPipeline(apiEndpoint, csvFilePath) {
try {
console.log(`Starting API to CSV pipeline from ${apiEndpoint} to ${csvFilePath}...`);
// 1. 从API提取数据
const apiData = this.extractor.extractFromAPI(apiEndpoint);
// 2. 转换数据(过滤)
const filteredData = this.transformer.transform(apiData, 'filter');
// 3. 格式化为CSV
const csvData = this.transformer.format(filteredData, 'csv');
// 4. 保存到文件
const saveResult = this.loader.saveToFile(csvData, csvFilePath);
console.log('API to CSV pipeline completed successfully!');
return saveResult;
} catch (error) {
console.error('API to CSV pipeline failed:', error);
throw new Error('Pipeline execution failed');
}
}
// 复杂数据处理流程:多源聚合报告
async generateReport(sources, reportPath) {
try {
console.log(`Starting report generation from ${sources.length} sources...`);
// 1. 从多个源提取数据
const allData = [];
for (const source of sources) {
const data = this.extractor.extract(source);
allData.push(...data);
}
// 2. 聚合数据
const aggregatedData = this.transformer.transform(allData, 'aggregate');
// 3. 格式化为JSON
const jsonReport = this.transformer.format(aggregatedData, 'json');
// 4. 保存报告
const saveResult = this.loader.saveToFile(jsonReport, reportPath);
console.log('Report generation completed successfully!');
return { ...saveResult, reportData: aggregatedData };
} catch (error) {
console.error('Report generation failed:', error);
throw new Error('Failed to generate report');
}
}
}
// 使用示例
async function useETLPipeline() {
const pipeline = new ETLPipeline();
// 简单ETL流程
console.log('\nRunning simple ETL pipeline:');
await pipeline.processData('database', 'warehouse');
// API到CSV文件流程
console.log('\nRunning API to CSV pipeline:');
await pipeline.apiToCsvPipeline('https://api.example.com/data', 'output.csv');
// 生成多源报告
console.log('\nGenerating multi-source report:');
const reportResult = await pipeline.generateReport(['source1', 'source2', 'source3'], 'report.json');
console.log('Report result:', reportResult);
}
## 四、行为型设计模式
行为型设计模式关注对象之间的通信和职责分配,解决对象之间如何相互协作和分配职责的问题。以下是在Node.js中常用的行为型设计模式:
### 4.1 观察者模式(Observer Pattern)
观察者模式定义了对象之间的一对多依赖关系,当一个对象状态发生变化时,其所有依赖者都会自动收到通知并更新。在Node.js中,EventEmitter是观察者模式的典型实现。
#### 4.1.1 基本实现
```javascript
// 自定义观察者模式实现
class Observer {
constructor() {
this.observers = [];
}
subscribe(observer) {
if (typeof observer === 'function') {
this.observers.push(observer);
return () => this.unsubscribe(observer);
}
throw new Error('Observer must be a function');
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => {
try {
observer(data);
} catch (error) {
console.error('Error in observer:', error);
}
});
}
}
// 使用示例
function useObserver() {
const subject = new Observer();
// 订阅观察者
const unsubscribe1 = subject.subscribe(data => {
console.log('Observer 1 received:', data);
});
const unsubscribe2 = subject.subscribe(data => {
console.log('Observer 2 received:', data);
});
// 发送通知
subject.notify('Hello world!');
// 取消订阅
unsubscribe1();
// 再次发送通知
subject.notify('Observer 1 should not receive this');
}
4.1.2 Node.js EventEmitter的应用
const EventEmitter = require('events');
class UserService extends EventEmitter {
constructor() {
super();
this.users = [];
}
createUser(userData) {
console.log('Creating user:', userData);
const user = { id: Date.now(), ...userData };
this.users.push(user);
// 触发事件通知
this.emit('userCreated', user);
return user;
}
updateUser(id, updates) {
const index = this.users.findIndex(user => user.id === id);
if (index !== -1) {
this.users[index] = { ...this.users[index], ...updates };
this.emit('userUpdated', this.users[index]);
return this.users[index];
}
this.emit('userUpdateFailed', { id, error: 'User not found' });
return null;
}
}
// 使用示例
function useEventEmitter() {
const userService = new UserService();
// 监听事件
userService.on('userCreated', user => {
console.log('New user created:', user);
// 可以在这里发送欢迎邮件、记录日志等
});
userService.on('userUpdated', user => {
console.log('User updated:', user);
});
userService.on('userUpdateFailed', data => {
console.error('Failed to update user:', data);
});
// 创建用户并触发事件
userService.createUser({ name: 'John Doe', email: 'john@example.com' });
// 更新用户并触发事件
userService.updateUser(12345, { name: 'Jane Doe' });
}
4.2 策略模式(Strategy Pattern)
策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互换使用。策略模式让算法的变化独立于使用算法的客户。
4.2.1 基本实现
// 策略接口
class PaymentStrategy {
pay(amount) {
throw new Error('Method not implemented');
}
}
// 具体策略:信用卡支付
class CreditCardPayment extends PaymentStrategy {
constructor(cardNumber, cardHolder) {
super();
this.cardNumber = cardNumber;
this.cardHolder = cardHolder;
}
pay(amount) {
console.log(`Processing credit card payment of $${amount} for ${this.cardHolder}`);
console.log(`Card number: ${this.maskCardNumber(this.cardNumber)}`);
return { success: true, paymentId: `cc_${Date.now()}` };
}
maskCardNumber(cardNumber) {
return '*'.repeat(cardNumber.length - 4) + cardNumber.slice(-4);
}
}
// 具体策略:PayPal支付
class PayPalPayment extends PaymentStrategy {
constructor(email) {
super();
this.email = email;
}
pay(amount) {
console.log(`Processing PayPal payment of $${amount} to ${this.email}`);
return { success: true, paymentId: `pp_${Date.now()}` };
}
}
// 具体策略:加密货币支付
class CryptoPayment extends PaymentStrategy {
constructor(walletAddress, currency) {
super();
this.walletAddress = walletAddress;
this.currency = currency;
}
pay(amount) {
console.log(`Processing ${this.currency} payment of $${amount}`);
console.log(`Wallet address: ${this.maskWalletAddress(this.walletAddress)}`);
return { success: true, paymentId: `crypto_${Date.now()}` };
}
maskWalletAddress(address) {
return address.slice(0, 6) + '...' + address.slice(-4);
}
}
// 上下文类
class PaymentContext {
constructor() {
this.strategy = null;
}
setPaymentStrategy(strategy) {
this.strategy = strategy;
}
executePayment(amount) {
if (!this.strategy) {
throw new Error('Payment strategy not set');
}
return this.strategy.pay(amount);
}
}
// 使用示例
function usePaymentStrategies() {
const paymentContext = new PaymentContext();
// 使用信用卡支付
paymentContext.setPaymentStrategy(new CreditCardPayment('1234567890123456', 'John Doe'));
const ccResult = paymentContext.executePayment(100);
console.log('Credit card payment result:', ccResult);
// 切换到PayPal支付
paymentContext.setPaymentStrategy(new PayPalPayment('john@example.com'));
const ppResult = paymentContext.executePayment(50);
console.log('PayPal payment result:', ppResult);
// 切换到加密货币支付
paymentContext.setPaymentStrategy(new CryptoPayment('0x1234567890abcdef1234567890abcdef12345678', 'ETH'));
const cryptoResult = paymentContext.executePayment(200);
console.log('Crypto payment result:', cryptoResult);
}
### 4.3 命令模式(Command Pattern)
命令模式将请求封装为一个对象,从而使您可以用不同的请求参数化客户端,队列或记录请求,并支持可撤销操作。这对于实现事务性操作、队列系统等非常有用。
#### 4.3.1 基本实现
```javascript
// 命令接口
class Command {
execute() {
throw new Error('Method not implemented');
}
undo() {
throw new Error('Method not implemented');
}
}
// 具体命令:创建用户
class CreateUserCommand extends Command {
constructor(userService, userData) {
super();
this.userService = userService;
this.userData = userData;
this.createdUserId = null;
}
execute() {
console.log('Executing CreateUserCommand');
const user = this.userService.createUser(this.userData);
this.createdUserId = user.id;
return user;
}
undo() {
if (this.createdUserId) {
console.log('Undoing CreateUserCommand for user ID:', this.createdUserId);
this.userService.deleteUser(this.createdUserId);
this.createdUserId = null;
}
}
}
// 具体命令:更新用户
class UpdateUserCommand extends Command {
constructor(userService, userId, updates) {
super();
this.userService = userService;
this.userId = userId;
this.updates = updates;
this.originalUserData = null;
}
execute() {
console.log('Executing UpdateUserCommand for user ID:', this.userId);
// 保存原始数据以便撤销
this.originalUserData = { ...this.userService.getUser(this.userId) };
return this.userService.updateUser(this.userId, this.updates);
}
undo() {
if (this.originalUserData) {
console.log('Undoing UpdateUserCommand for user ID:', this.userId);
this.userService.updateUser(this.userId, this.originalUserData);
this.originalUserData = null;
}
}
}
// 调用者类(命令队列)
class CommandInvoker {
constructor() {
this.commandHistory = [];
this.redoStack = [];
}
executeCommand(command) {
const result = command.execute();
this.commandHistory.push(command);
// 清空重做栈
this.redoStack = [];
return result;
}
undo() {
if (this.commandHistory.length === 0) {
console.log('Nothing to undo');
return;
}
const command = this.commandHistory.pop();
command.undo();
this.redoStack.push(command);
}
redo() {
if (this.redoStack.length === 0) {
console.log('Nothing to redo');
return;
}
const command = this.redoStack.pop();
command.execute();
this.commandHistory.push(command);
}
}
// 接收者类
class UserService {
constructor() {
this.users = new Map();
}
createUser(userData) {
const id = Date.now().toString();
const user = { id, ...userData };
this.users.set(id, user);
console.log('User created:', user);
return user;
}
getUser(id) {
return this.users.get(id) || null;
}
updateUser(id, updates) {
if (!this.users.has(id)) {
throw new Error(`User with id ${id} not found`);
}
const user = this.users.get(id);
const updatedUser = { ...user, ...updates };
this.users.set(id, updatedUser);
console.log('User updated:', updatedUser);
return updatedUser;
}
deleteUser(id) {
if (!this.users.has(id)) {
throw new Error(`User with id ${id} not found`);
}
const user = this.users.get(id);
this.users.delete(id);
console.log('User deleted:', user);
return user;
}
}
// 使用示例
function useCommandPattern() {
const userService = new UserService();
const invoker = new CommandInvoker();
// 创建并执行命令
const createCommand = new CreateUserCommand(
userService,
{ name: 'John Doe', email: 'john@example.com' }
);
const user = invoker.executeCommand(createCommand);
// 执行更新命令
const updateCommand = new UpdateUserCommand(
userService,
user.id,
{ name: 'Jane Doe', role: 'admin' }
);
invoker.executeCommand(updateCommand);
// 撤销最后一个命令
invoker.undo();
// 重做被撤销的命令
invoker.redo();
}
4.3.2 在Node.js中的应用示例
以下是命令模式在Node.js后端应用中的实际应用场景:
// 文件系统操作命令模式实现
const fs = require('fs').promises;
// 基础命令类
class FileCommand {
constructor(path) {
this.path = path;
this.originalContent = null;
}
async execute() {
throw new Error('Method not implemented');
}
async undo() {
throw new Error('Method not implemented');
}
}
// 创建文件命令
class CreateFileCommand extends FileCommand {
constructor(path, content = '') {
super(path);
this.content = content;
this.fileExisted = false;
}
async execute() {
try {
// 检查文件是否已存在
await fs.access(this.path);
this.fileExisted = true;
this.originalContent = await fs.readFile(this.path, 'utf8');
} catch (error) {
// 文件不存在,正常情况
this.fileExisted = false;
}
await fs.writeFile(this.path, this.content);
console.log(`File created or overwritten: ${this.path}`);
}
async undo() {
if (this.fileExisted) {
// 如果文件原本存在,恢复其内容
await fs.writeFile(this.path, this.originalContent);
console.log(`File restored to original content: ${this.path}`);
} else {
// 如果文件原本不存在,删除它
try {
await fs.unlink(this.path);
console.log(`File deleted: ${this.path}`);
} catch (error) {
console.error(`Failed to delete file: ${error.message}`);
}
}
}
}
// 追加文件命令
class AppendFileCommand extends FileCommand {
constructor(path, content) {
super(path);
this.content = content;
this.fileSizeBefore = 0;
}
async execute() {
try {
// 获取文件大小
const stats = await fs.stat(this.path);
this.fileSizeBefore = stats.size;
} catch (error) {
// 文件不存在
this.fileSizeBefore = 0;
}
await fs.appendFile(this.path, this.content);
console.log(`Content appended to file: ${this.path}`);
}
async undo() {
try {
// 读取文件内容
const content = await fs.readFile(this.path, 'utf8');
// 截取到追加前的大小
const newContent = content.substring(0, this.fileSizeBefore);
// 写回文件
await fs.writeFile(this.path, newContent);
console.log(`File reverted to state before append: ${this.path}`);
} catch (error) {
console.error(`Failed to revert file append: ${error.message}`);
}
}
}
// 文件操作命令管理器
class FileCommandManager {
constructor() {
this.history = [];
}
async execute(command) {
await command.execute();
this.history.push(command);
}
async undoLast() {
if (this.history.length === 0) {
console.log('No commands to undo');
return false;
}
const command = this.history.pop();
await command.undo();
return true;
}
async undoAll() {
while (this.history.length > 0) {
await this.undoLast();
}
}
}
// 使用示例:事务性文件操作
async function transactionalFileOperations() {
const manager = new FileCommandManager();
try {
// 创建第一个文件
const createCmd1 = new CreateFileCommand(
'./temp/file1.txt',
'This is the first file content.\n'
);
await manager.execute(createCmd1);
// 创建第二个文件
const createCmd2 = new CreateFileCommand(
'./temp/file2.txt',
'This is the second file content.\n'
);
await manager.execute(createCmd2);
// 追加内容到第一个文件
const appendCmd = new AppendFileCommand(
'./temp/file1.txt',
'Additional content appended.\n'
);
await manager.execute(appendCmd);
console.log('All file operations completed successfully!');
} catch (error) {
console.error('Error during file operations:', error);
console.log('Rolling back all changes...');
await manager.undoAll();
console.log('Rollback completed.');
}
}
### 4.4 迭代器模式(Iterator Pattern)
迭代器模式提供了一种方法来访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示。在JavaScript和Node.js中,迭代器模式已经被原生支持,例如通过Symbol.iterator接口。
#### 4.4.1 基本实现
```javascript
// 自定义迭代器实现
class CustomIterator {
constructor(data) {
this.data = data;
this.index = 0;
}
// 迭代器协议:返回包含next方法的对象
[Symbol.iterator]() {
return this;
}
// next方法返回{value: T, done: boolean}格式的对象
next() {
if (this.index < this.data.length) {
return {
value: this.data[this.index++],
done: false
};
} else {
return {
value: undefined,
done: true
};
}
}
// 重置迭代器
reset() {
this.index = 0;
}
// 跳过指定数量的元素
skip(count) {
this.index = Math.min(this.index + count, this.data.length);
}
}
// 可迭代集合类
class DataCollection {
constructor() {
this.items = [];
}
add(item) {
this.items.push(item);
return this;
}
remove(index) {
if (index >= 0 && index < this.items.length) {
this.items.splice(index, 1);
}
return this;
}
// 返回迭代器
getIterator() {
return new CustomIterator(this.items);
}
// 使集合自身可迭代
[Symbol.iterator]() {
return new CustomIterator(this.items);
}
// 筛选功能
filter(predicate) {
const filtered = new DataCollection();
for (const item of this.items) {
if (predicate(item)) {
filtered.add(item);
}
}
return filtered;
}
}
// 使用示例
function useIteratorPattern() {
const collection = new DataCollection();
// 添加数据
collection.add({ id: 1, name: 'Item 1' })
.add({ id: 2, name: 'Item 2' })
.add({ id: 3, name: 'Item 3' })
.add({ id: 4, name: 'Item 4' });
// 使用for...of循环(利用Symbol.iterator)
console.log('Using for...of loop:');
for (const item of collection) {
console.log(item);
}
// 使用自定义迭代器
console.log('\nUsing custom iterator:');
const iterator = collection.getIterator();
iterator.skip(1); // 跳过第一个元素
let result = iterator.next();
while (!result.done) {
console.log(result.value);
result = iterator.next();
}
// 使用筛选功能
console.log('\nFiltered items (id > 2):');
const filtered = collection.filter(item => item.id > 2);
for (const item of filtered) {
console.log(item);
}
}
4.4.2 在Node.js流处理中的应用
// 异步迭代器和流处理
const { Readable } = require('stream');
// 创建自定义可读流
class AsyncDataGenerator extends Readable {
constructor(options = {}) {
super({
objectMode: true, // 启用对象模式
...options
});
this.current = 0;
this.maxItems = options.maxItems || 10;
}
_read() {
// 模拟异步数据生成
setTimeout(() => {
if (this.current < this.maxItems) {
const data = {
id: this.current + 1,
timestamp: new Date().toISOString(),
value: Math.random() * 100
};
// 将数据推送到流中
const canContinue = this.push(data);
this.current++;
// 如果流要求停止推送(背压),则停止生成
if (!canContinue) {
console.log('Backpressure detected, pausing data generation');
}
} else {
// 没有更多数据时,关闭流
this.push(null);
}
}, 100); // 每100ms生成一个数据项
}
}
// 异步数据处理器
class AsyncDataProcessor {
constructor(transformFn) {
this.transformFn = transformFn || (data => data);
}
// 异步迭代处理
async processStream(stream) {
const results = [];
// 使用for await...of循环处理异步迭代器
for await (const chunk of stream) {
const processed = this.transformFn(chunk);
results.push(processed);
console.log('Processed item:', processed);
}
return results;
}
// 批量处理
async processBatch(stream, batchSize = 5) {
const results = [];
let batch = [];
let count = 0;
for await (const chunk of stream) {
batch.push(chunk);
count++;
if (count >= batchSize) {
const processedBatch = await this._processBatch(batch);
results.push(...processedBatch);
batch = [];
count = 0;
}
}
// 处理剩余的批次
if (batch.length > 0) {
const processedBatch = await this._processBatch(batch);
results.push(...processedBatch);
}
return results;
}
// 内部批次处理方法
async _processBatch(batch) {
console.log(`Processing batch of ${batch.length} items`);
// 模拟异步处理
await new Promise(resolve => setTimeout(resolve, 200));
return batch.map(item => this.transformFn(item));
}
}
// 使用示例
async function processDataStream() {
// 创建数据流
const dataStream = new AsyncDataGenerator({ maxItems: 12 });
// 创建处理器(转换数据)
const processor = new AsyncDataProcessor(item => ({
...item,
processed: true,
value: Math.round(item.value)
}));
console.log('Starting stream processing...');
try {
// 处理流数据
const results = await processor.processBatch(dataStream, 4);
console.log('\nProcessing complete!');
console.log(`Total items processed: ${results.length}`);
console.log('Final results sample:', results.slice(0, 2));
} catch (error) {
console.error('Error processing data stream:', error);
}
}
### 4.5 中介者模式(Mediator Pattern)
中介者模式定义了一个对象,封装了一组对象之间的交互方式,使这些对象之间不需要显式地相互引用,从而降低它们之间的耦合度。在Node.js应用中,中介者模式常用于事件总线、消息中心等组件。
#### 4.5.1 基本实现
```javascript
// 中介者类
class Mediator {
constructor() {
this.colleagues = new Map();
this.channels = new Map(); // 用于分组通信
}
// 注册同事对象
register(colleague, id = null) {
const colleagueId = id || colleague.id || Symbol('colleague');
this.colleagues.set(colleagueId, colleague);
// 为同事设置中介者引用
colleague.setMediator(this);
return colleagueId;
}
// 取消注册
unregister(id) {
const colleague = this.colleagues.get(id);
if (colleague) {
colleague.setMediator(null);
this.colleagues.delete(id);
return true;
}
return false;
}
// 向特定同事发送消息
sendMessage(message, fromId, toId) {
const recipient = this.colleagues.get(toId);
if (recipient) {
recipient.receiveMessage(message, fromId);
return true;
}
return false;
}
// 广播消息
broadcast(message, fromId) {
this.colleagues.forEach((colleague, id) => {
if (id !== fromId) {
colleague.receiveMessage(message, fromId);
}
});
}
// 加入频道
joinChannel(channel, colleagueId) {
if (!this.channels.has(channel)) {
this.channels.set(channel, new Set());
}
this.channels.get(channel).add(colleagueId);
}
// 离开频道
leaveChannel(channel, colleagueId) {
if (this.channels.has(channel)) {
this.channels.get(channel).delete(colleagueId);
// 如果频道为空,删除频道
if (this.channels.get(channel).size === 0) {
this.channels.delete(channel);
}
}
}
// 向频道广播消息
channelBroadcast(message, fromId, channel) {
if (this.channels.has(channel)) {
this.channels.get(channel).forEach(id => {
if (id !== fromId) {
const colleague = this.colleagues.get(id);
if (colleague) {
colleague.receiveMessage(message, fromId);
}
}
});
}
}
}
// 同事基类
class Colleague {
constructor(id = null) {
this.id = id;
this.mediator = null;
}
setMediator(mediator) {
this.mediator = mediator;
}
sendMessage(message, toId) {
if (this.mediator) {
this.mediator.sendMessage(message, this.id, toId);
}
}
broadcast(message) {
if (this.mediator) {
this.mediator.broadcast(message, this.id);
}
}
receiveMessage(message, fromId) {
console.log(`Colleague ${this.id} received from ${fromId}:`, message);
}
joinChannel(channel) {
if (this.mediator) {
this.mediator.joinChannel(channel, this.id);
}
}
leaveChannel(channel) {
if (this.mediator) {
this.mediator.leaveChannel(channel, this.id);
}
}
sendToChannel(message, channel) {
if (this.mediator) {
this.mediator.channelBroadcast(message, this.id, channel);
}
}
}
// 具体同事类:用户
class User extends Colleague {
constructor(id, name) {
super(id);
this.name = name;
this.messages = [];
}
receiveMessage(message, fromId) {
const msg = { from: fromId, content: message, time: new Date() };
this.messages.push(msg);
console.log(`[${this.name}] Received from ${fromId}:`, message);
}
getMessageHistory() {
return this.messages;
}
}
// 使用示例
function useMediatorPattern() {
const chatMediator = new Mediator();
// 创建用户(同事)
const alice = new User('alice', 'Alice');
const bob = new User('bob', 'Bob');
const charlie = new User('charlie', 'Charlie');
// 注册用户到中介者
chatMediator.register(alice);
chatMediator.register(bob);
chatMediator.register(charlie);
// 用户加入频道
alice.joinChannel('developers');
bob.joinChannel('developers');
bob.joinChannel('designers');
charlie.joinChannel('designers');
// 发送私聊消息
console.log('--- Private Messages ---');
alice.sendMessage('Hello Bob!', 'bob');
// 广播消息
console.log('\n--- Broadcast Messages ---');
charlie.broadcast('Hello everyone!');
// 频道消息
console.log('\n--- Channel Messages ---');
alice.sendToChannel('Any developers around?', 'developers');
charlie.sendToChannel('Design team meeting at 2pm', 'designers');
// 检查消息历史
console.log('\n--- Alice\'s Message History ---');
console.log(alice.getMessageHistory().length, 'messages received');
}