JavaScript设计模式详解

# JavaScript设计模式详解

## 1. 设计模式的基本概念

### 1.1 什么是设计模式

设计模式是在软件开发中针对特定问题的可重用解决方案,是经过验证的最佳实践。它们提供了一种标准化的方法来解决常见的设计问题。

### 1.2 设计模式的分类

– **创建型模式**:处理对象的创建过程
– **结构型模式**:处理对象之间的组合关系
– **行为型模式**:处理对象之间的交互和责任分配

### 1.3 设计模式的重要性

– **提高代码可维护性**:标准化的解决方案更容易理解和维护
– **提高代码可重用性**:模式可以在不同项目中重复使用
– **促进团队协作**:共享的设计语言便于团队成员之间的沟通
– **减少错误**:经过验证的模式可以避免常见的设计错误

## 2. 创建型模式

### 2.1 单例模式(Singleton)

**目的**:确保一个类只有一个实例,并提供一个全局访问点。

**实现**:

“`javascript
class Singleton {
constructor() {
if (Singleton.instance) {
return Singleton.instance;
}
Singleton.instance = this;
// 初始化代码
}

static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}

// 使用
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true

const instance3 = Singleton.getInstance();
console.log(instance1 === instance3); // true
“`

**应用场景**:
– 全局配置对象
– 数据库连接池
– 日志记录器
– 缓存

### 2.2 工厂模式(Factory)

**目的**:提供一个创建对象的接口,让子类决定要实例化的类是哪一个。

**实现**:

“`javascript
class Product {
constructor(name) {
this.name = name;
}

operation() {
return `Operation from ${this.name}`;
}
}

class ConcreteProductA extends Product {
constructor() {
super(‘Product A’);
}
}

class ConcreteProductB extends Product {
constructor() {
super(‘Product B’);
}
}

class Factory {
createProduct(type) {
switch (type) {
case ‘A’:
return new ConcreteProductA();
case ‘B’:
return new ConcreteProductB();
default:
throw new Error(‘Invalid product type’);
}
}
}

// 使用
const factory = new Factory();
const productA = factory.createProduct(‘A’);
const productB = factory.createProduct(‘B’);
console.log(productA.operation()); // Operation from Product A
console.log(productB.operation()); // Operation from Product B
“`

**应用场景**:
– 复杂对象的创建
– 基于配置或环境创建不同类型的对象
– 库和框架的API设计

### 2.3 构建者模式(Builder)

**目的**:将复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。

**实现**:

“`javascript
class Product {
constructor() {
this.parts = [];
}

add(part) {
this.parts.push(part);
}

listParts() {
return `Product parts: ${this.parts.join(‘, ‘)}`;
}
}

class Builder {
constructor() {
this.reset();
}

reset() {
this.product = new Product();
}

buildPartA() {
this.product.add(‘Part A’);
return this;
}

buildPartB() {
this.product.add(‘Part B’);
return this;
}

buildPartC() {
this.product.add(‘Part C’);
return this;
}

getProduct() {
const result = this.product;
this.reset();
return result;
}
}

// 使用
const builder = new Builder();
const product1 = builder.buildPartA().buildPartB().getProduct();
console.log(product1.listParts()); // Product parts: Part A, Part B

const product2 = builder.buildPartB().buildPartC().getProduct();
console.log(product2.listParts()); // Product parts: Part B, Part C
“`

**应用场景**:
– 复杂对象的构建
– 需要多个步骤创建对象
– 对象有多个可选参数

### 2.4 原型模式(Prototype)

**目的**:通过复制现有对象来创建新对象,而不是通过实例化类。

**实现**:

“`javascript
class Prototype {
constructor(proto) {
this.proto = proto;
}

clone() {
return Object.create(this.proto);
}
}

// 使用
const original = {
name: ‘Original’,
sayHello() {
return `Hello from ${this.name}`;
}
};

const prototype = new Prototype(original);
const clone1 = prototype.clone();
clone1.name = ‘Clone 1’;
console.log(clone1.sayHello()); // Hello from Clone 1

const clone2 = prototype.clone();
clone2.name = ‘Clone 2’;
console.log(clone2.sayHello()); // Hello from Clone 2
“`

**应用场景**:
– 对象创建成本高
– 需要动态创建对象
– 对象配置复杂

## 3. 结构型模式

### 3.1 适配器模式(Adapter)

**目的**:将一个类的接口转换为客户端期望的另一个接口,使得原本不兼容的类可以一起工作。

**实现**:

“`javascript
// 目标接口
class Target {
request() {
return ‘Target: Default behavior’;
}
}

// 被适配的类
class Adaptee {
specificRequest() {
return ‘.eetpadA eht fo roivaheb laicepS’;
}
}

// 适配器
class Adapter extends Target {
constructor(adaptee) {
super();
this.adaptee = adaptee;
}

request() {
const result = this.adaptee.specificRequest();
return `Adapter: (TRANSLATED) ${result.split(”).reverse().join(”)}`;
}
}

// 使用
function clientCode(target) {
console.log(target.request());
}

const target = new Target();
clientCode(target); // Target: Default behavior

const adaptee = new Adaptee();
const adapter = new Adapter(adaptee);
clientCode(adapter); // Adapter: (TRANSLATED) Specific behavior of the Adaptee
“`

**应用场景**:
– 集成第三方库
– 向后兼容旧接口
– 系统重构

### 3.2 装饰器模式(Decorator)

**目的**:动态地给对象添加额外的责任,而不修改其结构。

**实现**:

“`javascript
class Component {
operation() {
return ‘Component operation’;
}
}

class Decorator extends Component {
constructor(component) {
super();
this.component = component;
}

operation() {
return this.component.operation();
}
}

class ConcreteDecoratorA extends Decorator {
operation() {
return `ConcreteDecoratorA(${super.operation()})`;
}
}

class ConcreteDecoratorB extends Decorator {
operation() {
return `ConcreteDecoratorB(${super.operation()})`;
}
}

// 使用
const component = new Component();
console.log(component.operation()); // Component operation

const decoratorA = new ConcreteDecoratorA(component);
console.log(decoratorA.operation()); // ConcreteDecoratorA(Component operation)

const decoratorB = new ConcreteDecoratorB(decoratorA);
console.log(decoratorB.operation()); // ConcreteDecoratorB(ConcreteDecoratorA(Component operation))
“`

**应用场景**:
– 功能扩展
– 动态添加责任
– 避免子类爆炸

### 3.3 代理模式(Proxy)

**目的**:为其他对象提供一个代理,以控制对这个对象的访问。

**实现**:

“`javascript
class Subject {
request() {
return ‘Subject: Handling request’;
}
}

class Proxy extends Subject {
constructor(subject) {
super();
this.subject = subject;
}

request() {
if (this.checkAccess()) {
const result = this.subject.request();
this.logAccess();
return result;
}
return ‘Proxy: Access denied’;
}

checkAccess() {
console.log(‘Proxy: Checking access prior to sending a request’);
return true;
}

logAccess() {
console.log(‘Proxy: Logging the time of request’);
}
}

// 使用
function clientCode(subject) {
console.log(subject.request());
}

const realSubject = new Subject();
console.log(‘Client: Executing the client code with a real subject:’);
clientCode(realSubject);

console.log(‘\nClient: Executing the same client code with a proxy:’);
const proxy = new Proxy(realSubject);
clientCode(proxy);
“`

**应用场景**:
– 访问控制
– 缓存
– 延迟加载
– 日志记录

### 3.4 组合模式(Composite)

**目的**:将对象组合成树形结构以表示”部分-整体”的层次结构,使得客户端可以统一处理单个对象和对象组合。

**实现**:

“`javascript
class Component {
constructor(name) {
this.name = name;
}

add(component) {
throw new Error(‘Method not implemented’);
}

remove(component) {
throw new Error(‘Method not implemented’);
}

display(depth = 0) {
throw new Error(‘Method not implemented’);
}
}

class Leaf extends Component {
display(depth) {
console.log(‘ ‘.repeat(depth) + `- ${this.name}`);
}
}

class Composite extends Component {
constructor(name) {
super(name);
this.children = [];
}

add(component) {
this.children.push(component);
}

remove(component) {
const index = this.children.indexOf(component);
if (index !== -1) {
this.children.splice(index, 1);
}
}

display(depth) {
console.log(‘ ‘.repeat(depth) + `+ ${this.name}`);
for (const child of this.children) {
child.display(depth + 2);
}
}
}

// 使用
const root = new Composite(‘Root’);
root.add(new Leaf(‘Leaf A’));

const composite = new Composite(‘Composite’);
composite.add(new Leaf(‘Leaf B’));
composite.add(new Leaf(‘Leaf C’));

root.add(composite);
root.add(new Leaf(‘Leaf D’));

root.display();
// + Root
// – Leaf A
// + Composite
// – Leaf B
// – Leaf C
// – Leaf D
“`

**应用场景**:
– 树形结构
– 菜单系统
– 组件层次结构
– 文件系统

## 4. 行为型模式

### 4.1 观察者模式(Observer)

**目的**:定义对象间的一种一对多依赖关系,使得每当一个对象状态发生变化时,其相关依赖对象都得到通知并被自动更新。

**实现**:

“`javascript
class Subject {
constructor() {
this.observers = [];
}

attach(observer) {
this.observers.push(observer);
}

detach(observer) {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}

notify() {
for (const observer of this.observers) {
observer.update(this);
}
}
}

class ConcreteSubject extends Subject {
constructor() {
super();
this.state = 0;
}

getState() {
return this.state;
}

setState(state) {
this.state = state;
this.notify();
}
}

class Observer {
update(subject) {
throw new Error(‘Method not implemented’);
}
}

class ConcreteObserverA extends Observer {
update(subject) {
if (subject.state < 3) { console.log('ConcreteObserverA: Reacted to the event'); } } } class ConcreteObserverB extends Observer { update(subject) { if (subject.state === 2 || subject.state === 3) { console.log('ConcreteObserverB: Reacted to the event'); } } } // 使用 const subject = new ConcreteSubject(); const observerA = new ConcreteObserverA(); subject.attach(observerA); const observerB = new ConcreteObserverB(); subject.attach(observerB); subject.setState(1); // ConcreteObserverA: Reacted to the event subject.setState(2); // ConcreteObserverA: Reacted to the event, ConcreteObserverB: Reacted to the event subject.setState(3); // ConcreteObserverB: Reacted to the event ``` **应用场景**: - 事件处理系统 - 发布-订阅模式 - 数据绑定 - 消息队列 ### 4.2 策略模式(Strategy) **目的**:定义一系列算法,把它们封装起来,并且使它们可以互相替换。 **实现**: ```javascript class Strategy { execute(a, b) { throw new Error('Method not implemented'); } } class ConcreteStrategyA extends Strategy { execute(a, b) { return a + b; } } class ConcreteStrategyB extends Strategy { execute(a, b) { return a - b; } } class ConcreteStrategyC extends Strategy { execute(a, b) { return a * b; } } class Context { constructor(strategy) { this.strategy = strategy; } setStrategy(strategy) { this.strategy = strategy; } executeStrategy(a, b) { return this.strategy.execute(a, b); } } // 使用 const context = new Context(new ConcreteStrategyA()); console.log('10 + 5 =', context.executeStrategy(10, 5)); // 10 + 5 = 15 context.setStrategy(new ConcreteStrategyB()); console.log('10 - 5 =', context.executeStrategy(10, 5)); // 10 - 5 = 5 context.setStrategy(new ConcreteStrategyC()); console.log('10 * 5 =', context.executeStrategy(10, 5)); // 10 * 5 = 50 ``` **应用场景**: - 算法选择 - 排序策略 - 验证规则 - 支付方式 ### 4.3 命令模式(Command) **目的**:将请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 **实现**: ```javascript class Command { execute() { throw new Error('Method not implemented'); } undo() { throw new Error('Method not implemented'); } } class Receiver { action() { return 'Receiver: Action performed'; } undoAction() { return 'Receiver: Action undone'; } } class ConcreteCommand extends Command { constructor(receiver) { super(); this.receiver = receiver; } execute() { return this.receiver.action(); } undo() { return this.receiver.undoAction(); } } class Invoker { constructor() { this.command = null; } setCommand(command) { this.command = command; } executeCommand() { if (this.command) { return this.command.execute(); } return 'No command set'; } undoCommand() { if (this.command) { return this.command.undo(); } return 'No command set'; } } // 使用 const receiver = new Receiver(); const command = new ConcreteCommand(receiver); const invoker = new Invoker(); invoker.setCommand(command); console.log(invoker.executeCommand()); // Receiver: Action performed console.log(invoker.undoCommand()); // Receiver: Action undone ``` **应用场景**: - 撤销/重做操作 - 队列请求 - 日志记录 - 事务处理 ### 4.4 迭代器模式(Iterator) **目的**:提供一种方法来访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示。 **实现**: ```javascript class Iterator { hasNext() { throw new Error('Method not implemented'); } next() { throw new Error('Method not implemented'); } } class ConcreteIterator extends Iterator { constructor(collection) { super(); this.collection = collection; this.index = 0; } hasNext() { return this.index < this.collection.count(); } next() { if (this.hasNext()) { return this.collection.getItems()[this.index++]; } return null; } } class Aggregate { createIterator() { throw new Error('Method not implemented'); } } class ConcreteAggregate extends Aggregate { constructor() { super(); this.items = []; } addItem(item) { this.items.push(item); } getItems() { return this.items; } count() { return this.items.length; } createIterator() { return new ConcreteIterator(this); } } // 使用 const aggregate = new ConcreteAggregate(); aggregate.addItem('Item 1'); aggregate.addItem('Item 2'); aggregate.addItem('Item 3'); const iterator = aggregate.createIterator(); while (iterator.hasNext()) { console.log(iterator.next()); } // Item 1 // Item 2 // Item 3 ``` **应用场景**: - 遍历集合 - 统一遍历接口 - 延迟加载 ### 4.5 模板方法模式(Template Method) **目的**:定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。 **实现**: ```javascript class AbstractClass { templateMethod() { this.baseOperation1(); this.requiredOperation1(); this.baseOperation2(); this.hook1(); this.requiredOperation2(); this.baseOperation3(); this.hook2(); } baseOperation1() { console.log('AbstractClass: Base operation 1'); } baseOperation2() { console.log('AbstractClass: Base operation 2'); } baseOperation3() { console.log('AbstractClass: Base operation 3'); } hook1() {} hook2() {} requiredOperation1() { throw new Error('Subclass must implement abstract method'); } requiredOperation2() { throw new Error('Subclass must implement abstract method'); } } class ConcreteClass1 extends AbstractClass { requiredOperation1() { console.log('ConcreteClass1: Implemented operation 1'); } requiredOperation2() { console.log('ConcreteClass1: Implemented operation 2'); } hook1() { console.log('ConcreteClass1: Overridden hook 1'); } } class ConcreteClass2 extends AbstractClass { requiredOperation1() { console.log('ConcreteClass2: Implemented operation 1'); } requiredOperation2() { console.log('ConcreteClass2: Implemented operation 2'); } hook2() { console.log('ConcreteClass2: Overridden hook 2'); } } // 使用 function clientCode(abstractClass) { abstractClass.templateMethod(); } console.log('Client: Executing the template method with ConcreteClass1:'); clientCode(new ConcreteClass1()); console.log('\nClient: Executing the template method with ConcreteClass2:'); clientCode(new ConcreteClass2()); ``` **应用场景**: - 算法骨架 - 框架设计 - 代码复用 ## 5. JavaScript特有的设计模式 ### 5.1 模块模式(Module Pattern) **目的**:创建私有变量和方法,只暴露公共接口。 **实现**: ```javascript const Module = (function() { // 私有变量 let privateVariable = 0; // 私有方法 function privateMethod() { return 'Private method called'; } // 公共接口 return { publicMethod: function() { privateVariable++; return `Public method called, privateVariable: ${privateVariable}`; }, getPrivateVariable: function() { return privateVariable; } }; })(); // 使用 console.log(Module.publicMethod()); // Public method called, privateVariable: 1 console.log(Module.publicMethod()); // Public method called, privateVariable: 2 console.log(Module.getPrivateVariable()); // 2 console.log(Module.privateVariable); // undefined ``` ### 5.2 揭示模块模式(Revealing Module Pattern) **目的**:通过返回一个对象字面量来揭示公共接口,使代码更清晰。 **实现**: ```javascript const RevealingModule = (function() { // 私有变量 let privateVariable = 0; // 私有方法 function privateMethod() { return 'Private method called'; } // 公共方法 function publicMethod() { privateVariable++; return `Public method called, privateVariable: ${privateVariable}`; } function getPrivateVariable() { return privateVariable; } // 揭示公共接口 return { publicMethod: publicMethod, getPrivateVariable: getPrivateVariable }; })(); // 使用 console.log(RevealingModule.publicMethod()); // Public method called, privateVariable: 1 console.log(RevealingModule.getPrivateVariable()); // 1 ``` ### 5.3 混合模式(Mixin Pattern) **目的**:通过组合而不是继承来复用代码。 **实现**: ```javascript const Mixin = { sayHello() { return `Hello from ${this.name}`; }, sayGoodbye() { return `Goodbye from ${this.name}`; } }; class Person { constructor(name) { this.name = name; } } // 应用混合 Object.assign(Person.prototype, Mixin); // 使用 const person = new Person('John'); console.log(person.sayHello()); // Hello from John console.log(person.sayGoodbye()); // Goodbye from John ``` ### 5.4 单例模式的模块实现 **目的**:创建一个全局唯一的模块实例。 **实现**: ```javascript const SingletonModule = (function() { let instance; function createInstance() { // 模块初始化 return { publicMethod: function() { return 'Singleton method called'; }, publicProperty: 'Singleton property' }; } return { getInstance: function() { if (!instance) { instance = createInstance(); } return instance; } }; })(); // 使用 const instance1 = SingletonModule.getInstance(); const instance2 = SingletonModule.getInstance(); console.log(instance1 === instance2); // true console.log(instance1.publicMethod()); // Singleton method called ``` ## 6. 设计模式的最佳实践 ### 6.1 何时使用设计模式 - 当你遇到重复出现的设计问题时 - 当你需要提高代码可维护性时 - 当你需要与团队成员共享设计方案时 - 当你需要解决特定的设计挑战时 ### 6.2 设计模式的选择 - 根据问题类型选择合适的模式 - 考虑代码的复杂度和可维护性 - 考虑团队的熟悉程度 - 考虑性能影响 ### 6.3 设计模式的实现注意事项 - 不要过度使用设计模式 - 不要生搬硬套设计模式 - 确保模式的实现符合语言特性 - 保持代码简洁和可理解 ### 6.4 设计模式的演进 - 随着语言特性的变化调整模式实现 - 结合现代JavaScript特性(ES6+) - 适应不同的应用场景 ## 7. 总结 - **设计模式**是解决常见设计问题的可重用解决方案 - **创建型模式**处理对象的创建过程 - **结构型模式**处理对象之间的组合关系 - **行为型模式**处理对象之间的交互和责任分配 - **JavaScript特有的模式**充分利用了语言的特性 - **最佳实践**包括根据问题选择合适的模式,避免过度使用,保持代码简洁 通过掌握设计模式,我们可以编写更加可维护、可重用、可扩展的JavaScript代码。设计模式不仅是一种技术解决方案,也是一种思维方式,帮助我们更好地理解和设计软件系统。