代理模式允许开发者提供一个替代品或占位符来控制对原始对象的访问。这种模式通过创建一个代表原始对象的代理对象,可以在不改变原始对象代码的情况下,添加新的功能或控制对象的访问。
// 主题接口
class Image {
display() {
throw new Error('Method not implemented');
}
}
// 实际主题
class RealImage extends Image {
#filename;
constructor(filename) {
super();
this.#filename = filename;
this.loadFromDisk();
}
loadFromDisk() {
console.log(`Loading ${this.#filename} from disk`);
}
display() {
console.log(`Displaying ${this.#filename}`);
}
}
// 代理
class ProxyImage extends Image {
#filename;
#realImage;
constructor(filename) {
super();
this.#filename = filename;
}
display() {
if (!this.#realImage) {
this.#realImage = new RealImage(this.#filename);
}
this.#realImage.display();
}
}
// 图片管理器(使用代理的客户端)
class ImageManager {
#imageCache = new Map();
async loadImage(filename) {
if (!this.#imageCache.has(filename)) {
console.log(`Image ${filename} not in cache, creating proxy`);
this.#imageCache.set(filename, new ProxyImage(filename));
} else {
console.log(`Image ${filename} found in cache`);
}
return this.#imageCache.get(filename);
}
async displayImage(filename) {
const image = await this.loadImage(filename);
image.display();
}
}
// 使用示例
async function demonstrateProxy() {
const manager = new ImageManager();
console.log("First request for image1.jpg:");
await manager.displayImage('image1.jpg');
console.log("\nSecond request for image1.jpg:");
await manager.displayImage('image1.jpg');
console.log("\nFirst request for image2.jpg:");
await manager.displayImage('image2.jpg');
}
demonstrateProxy().catch(console.error);
实现思路
-
Image类:这是主题接口,定义了display方法。 -
RealImage类(实际主题):- 实现了
Image接口。 - 包含真实的图片加载和显示逻辑。
- 使用私有字段
#filename来存储文件名。
- 实现了
-
ProxyImage类(代理):- 也实现了
Image接口。 - 包含对
RealImage的引用,但只在需要时才创建。 - 控制对
RealImage的访问,实现了延迟加载。
- 也实现了
-
ImageManager类:- 使用
Map来缓存已创建的代理对象。 - 提供
loadImage方法来获取(或创建)图片的代理。 - 提供
displayImage方法来显示图片,内部使用代理。
- 使用
优点
- 延迟加载:当一个对象的创建成本很高时,代理模式可以延迟加载对象。
- 访问控制:当需要对敏感对象进行访问控制时,代理模式可以控制对对象的访问。
- 日志记录:代理模式可以用于保存对对象的所有访问的日志。
- 缓存:实现一个缓存系统来改善性能,减少重复加载。
- 智能引用:当没有客户端使用某个重量级对象时,可以立即销毁它以节省资源。