JavaScript 结构型模式详解
1. 代理模式
1.1. 使用场景
代理模式在不改变原始对象的前提下,通过代理对象控制对其访问,通常用于权限控制、延迟加载、远程调用等场景。在前端开发中,可以通过代理模式对网络请求、缓存机制等进行控制。
1.2. 代码实现
class ApiService {request() {console.log('Making API request...');return 'Response from API';}
}class ApiServiceProxy {constructor() {this.apiservice = new ApiService();this.cache = null;}request() {if (!this.cache) {console.log('Fetching from API...');this.cache = this.apiservice.request();} else {console.log('Returning cached response...');}return this.cache;}
}// 使用代理模式
const apiProxy = new ApiServiceProxy();
console.log(apiProxy.request()); // Fetching from API... Response from API
console.log(apiProxy.request()); // Returning cached response... Response from API
1.3. 详细注释
ApiService:表示原始对象,提供基础的 API 请求功能。
ApiServiceProxy:代理类,控制对 ApiService 的访问,缓存请求结果以避免多次 API 调用。
代理模式用于在不修改原始对象的情况下,添加缓存或权限控制等功能。
1.4. 实际应用
- 代理模式常用于缓存、权限管理、远程代理等场景,如在前端缓存 API 请求、延迟加载图片等。
2. 适配器模式
2.1. 使用场景
适配器模式用于将不兼容的接口转换为兼容的接口,解决不同对象或模块之间的兼容性问题。在前端开发中,适配器模式可用于将第三方库的接口适配为项目内部通用的接口形式。
2.2. 代码实现
class OldApi {oldRequest() {return 'Old API response';}
}class Adapter {constructor(oldApi) {this.oldApi = oldApi;}newRequest() {return this.oldApi.oldRequest();}
}// 使用适配器模式
const oldApi = new OldApi();
const adapter = new Adapter(oldApi);
console.log(adapter.newRequest()); // Old API response
2.3. 详细注释
OldApi:表示旧的接口,提供老旧的请求方式。
Adapter:适配器,将旧接口适配为新的接口,使得可以在新环境中使用旧的功能。
适配器模式解决了接口不兼容的问题,便于老旧代码与新代码的集成。
2.4. 实际应用
适配器模式常用于集成不同版本的接口或库,如将旧版 API 接口适配到新版项目中。
3. 装饰器模式
3.1. 使用场景
装饰器模式用于在不修改现有对象的情况下,动态地为其添加功能。在前端中,装饰器模式常用于为对象或函数动态添加功能,如事件处理、日志记录等。
3.2. 代码实现
class Coffee {cost() {return 5;}
}class MilkDecorator {constructor(coffee) {this.coffee = coffee;}cost() {return this.coffee.cost() + 1;}
}class SugarDecorator {constructor(coffee) {this.coffee = coffee;}cost() {return this.coffee.cost() + 0.5;}
}// 使用装饰器模式
let coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
console.log(coffee.cost()); // 6.5
3.3. 详细注释
Coffee:原始对象,表示基础的咖啡,提供基本功能。
MilkDecorator 和 SugarDecorator:装饰器类,动态为 Coffee 对象添加牛奶和糖的功能。
装饰器模式通过包装对象的方式,动态添加功能而不修改原始类。
3.3. 实际应用
装饰器模式常用于前端中动态功能的添加,如为按钮添加事件处理、为组件增加样式等。
4. 桥接模式
4.1. 使用场景
桥接模式用于将抽象部分和实现部分分离,使它们可以独立变化。常用于当一个对象有多个维度的变化时,将这些变化解耦。在前端开发中,桥接模式用于将功能和 UI 的实现分离,使得它们可以独立演进。
4.2. 代码实现
class Shape {constructor(color) {this.color = color;}draw() {throw new Error('draw() must be implemented');}
}class Circle extends Shape {draw() {console.log(`Drawing a ${this.color.getColor()} circle`);}
}class Color {getColor() {throw new Error('getColor() must be implemented');}
}class RedColor extends Color {getColor() {return 'red';}
}class BlueColor extends Color {getColor() {return 'blue';}
}// 使用桥接模式
const red = new RedColor();
const blue = new BlueColor();const redCircle = new Circle(red);
redCircle.draw(); // Drawing a red circleconst blueCircle = new Circle(blue);
blueCircle.draw(); // Drawing a blue circle
4.3. 详细注释
Shape:抽象类,定义了 draw 方法。
Circle:具体实现类,实现了 Shape 的 draw 方法。
Color:表示颜色抽象,可以有不同的颜色实现类如 RedColor 和 BlueColor。
桥接模式将形状和颜色的实现解耦,可以独立扩展。
4.4. 实际应用
桥接模式常用于将功能和实现分离,如在图形绘制中分离形状和颜色、在 UI 组件中分离外观和行为。
5. 组合模式
5.1. 使用场景
组合模式用于将对象组合成树形结构,以表示“部分-整体”的层次结构。前端中,组合模式常用于构建层次结构的 UI 组件,如菜单、文件夹结构等。
5.2. 代码实现
class MenuItem {constructor(name) {this.name = name;}show() {console.log(this.name);}
}class Menu {constructor(name) {this.name = name;this.items = [];}add(item) {this.items.push(item);}show() {console.log(this.name);this.items.forEach(item => item.show());}
}// 使用组合模式
const fileMenu = new Menu('File');
fileMenu.add(new MenuItem('New'));
fileMenu.add(new MenuItem('Open'));const editMenu = new Menu('Edit');
editMenu.add(new MenuItem('Undo'));
editMenu.add(new MenuItem('Redo'));const mainMenu = new Menu('Main Menu');
mainMenu.add(fileMenu);
mainMenu.add(editMenu);mainMenu.show();
5.3. 详细注释
MenuItem:表示基础菜单项,提供 show 方法。
Menu:组合类,包含多个 MenuItem 或其他 Menu,提供组合的 show 方法。
组合模式允许树形结构的对象组合和处理,实现部分与整体的递归处理。
5.4. 实际应用
组合模式常用于前端的树形结构、层次化菜单、文件目录管理等场景。
6. 外观模式
6.1. 使用场景
外观模式提供了一个简化的接口来访问复杂的系统,隐藏内部实现细节,减少客户端的复杂性。在前端开发中,外观模式常用于为复杂的库或系统提供简化的 API。
6.2. 代码实现
class Subsystem1 {operation() {return 'Subsystem1 operation';}
}class Subsystem2 {operation() {return 'Subsystem2 operation';}
}class Facade {constructor() {this.subsystem1 = new Subsystem1();this.subsystem2 = new Subsystem2();}operation() {return `${this.subsystem1.operation()} + ${this.subsystem2.operation()}`;}
}// 使用外观模式
const facade = new Facade();
console.log(facade.operation()); // Subsystem1 operation + Subsystem2 operation
6.3. 详细注释
Subsystem1 和 Subsystem2:表示复杂系统的部分。
Facade:外观类,提供简化的 operation 方法,统一调用多个子系统。
外观模式通过提供一个简化的接口,隐藏了复杂系统的细节。
6.4. 实际应用
外观模式常用于封装复杂的子系统,如封装多种 API 调用、封装复杂的 UI 逻辑等。
7. 享元模式
7.1. 使用场景
享元模式通过共享相同的对象来减少内存消耗,适用于需要大量相似对象的场景。在前端开发中,享元模式用于优化性能,如缓存对象、共享数据等。
7.2. 代码实现
class Flyweight {constructor(sharedState) {this.sharedState = sharedState;}operation(uniqueState) {console.log(`Shared: ${this.sharedState}, Unique: ${uniqueState}`);}
}class FlyweightFactory {constructor() {this.flyweights = {};}getFlyweight(sharedState) {if (!this.flyweights[sharedState]) {this.flyweights[sharedState] = new Flyweight(sharedState);}return this.flyweights[sharedState];}
}// 使用享元模式
const factory = new FlyweightFactory();const flyweight1 = factory.getFlyweight('Shared1');
flyweight1.operation('Unique1');const flyweight2 = factory.getFlyweight('Shared1');
flyweight2.operation('Unique2');console.log(flyweight1 === flyweight2); // true
7.3. 详细注释
Flyweight:享元对象,包含共享的状态 sharedState 。
FlyweightFactory:负责创建和管理共享的享元对象,避免重复创建相同的对象。
享元模式通过共享对象,减少了内存消耗,提升了系统性能。
7.4. 实际应用
享元模式常用于缓存机制、对象池、共享数据等需要大量相似对象的场景。