# 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代码。设计模式不仅是一种技术解决方案,也是一种思维方式,帮助我们更好地理解和设计软件系统。