代理模式是一种结构型模式,其中一个对象充当另一个对象的接口,以控制对该对象的访问。 这种类型的设计模式属于结构模式,它对对象进行组合,以提供新的功能,同时使代码更易于维护。
深入理解JavaScript系列(31):设计模式之代理模式详解
概述
代理模式是一种结构型模式,其中一个对象充当另一个对象的接口,以控制对该对象的访问。 这种类型的设计模式属于结构模式,它对对象进行组合,以提供新的功能,同时使代码更易于维护。
在 JavaScript 中,代理模式允许我们在运行时动态地创建对象并控制其行为。 代理可以隔离对实际对象的访问,并对外部世界提供它自己的访问方式,以限制直接访问实际对象。
代理模式的实现
代理模式通过创建代理对象对访问对象进行控制,代理对象与实际对象具有相同的接口,开发者可以通过代理对象访问实际对象。
代理对象
代理对象的作用是隐藏实际对象,以允许开发者访问实际对象的方法或属性,并在访问之前对访问请求进行处理。
代理对象与实际对象通常实现相同的接口,以便开发者可以在无需了解实际对象的情况下,使用代理对象访问实际对象。
class RealSubject {
someOperation() {
console.log("RealSubject.someOperation()");
}
}
class ProxySubject {
constructor(realSubject) {
this.realSubject = realSubject;
}
someOperation() {
console.log("ProxySubject.someOperation()");
//handle the privilege to real object
this.realSubject.someOperation();
}
}
// Client
const realSubject = new RealSubject();
const proxySubject = new ProxySubject(realSubject);
proxySubject.someOperation();
保护代理
保护代理可以控制实际对象对内部状态的访问,如果属性或者方法不应该被外部对象访问,可以使用保护代理。
下面的例子中,我们使用保护代理来防止直接访问 privateMethod
方法
class RealSubject {
someOperation() {
console.log("RealSubject.someOperation()");
}
privateMethod() {
console.log("RealSubject.privateMethod()");
}
}
class ProxySubject {
constructor(realSubject) {
this.realSubject = realSubject;
}
someOperation() {
console.log("ProxySubject.someOperation()");
//handle the privilege to real object
this.realSubject.someOperation();
//Cannot access to privateMethod from outside
}
}
// Client
const realSubject = new RealSubject();
const proxySubject = new ProxySubject(realSubject);
proxySubject.someOperation();
虚拟代理
虚拟代理是一种惰性加载模式,可以通过避免初始化真正对象来减少系统资源的使用。
下面的例子中,我们使用虚拟代理来加载视频
class VideoPlayer {
constructor(video) {
this.video = video;
}
play() {
console.log(`Playing video: ${this.video.name}`);
}
}
class VideoPlayerProxy {
constructor(video) {
this.video = video;
}
play() {
if (!this.videoPlayer) {
// Initialize the video player only when the user wants to play video
this.videoPlayer = new VideoPlayer(this.video);
}
this.videoPlayer.play();
}
}
// Client
const video = { name: "Introduction to Design Patterns" };
const videoPlayerProxy = new VideoPlayerProxy(video);
videoPlayerProxy.play();
总结
代理模式提供了访问受控对象的另一种方法,可以使用代理实现额外的功能或提供额外的保护。代理模式是一种非常常见的设计模式,它可以在需要对对象进行访问控制,缓存或记录日志时非常有用。
示例 1:代理模式用于日志系统
class BitcoinPrice {
constructor() {}
async getBitcoinPriceByCurrencyCode(currencyCode) {
const response = await fetch(
`https://api.coindesk.com/v1/bpi/currentprice/${currencyCode}.json`
);
const data = await response.json();
return data.bpi[currencyCode].rate_float;
}
}
class BitcoinPriceProxy {
constructor() {
this.bitcoinPrice = new BitcoinPrice();
}
async getBitcoinPriceByCurrencyCode(currencyCode) {
const price = await this.bitcoinPrice.getBitcoinPriceByCurrencyCode(
currencyCode
);
console.log(`Bitcoin price for ${currencyCode} is $${price}`);
return price;
}
}
// Client
const bitcoinPriceProxy = new BitcoinPriceProxy();
bitcoinPriceProxy.getBitcoinPriceByCurrencyCode("USD");
示例 2:代理模式用于缓存系统
class SomeContent {
constructor(contentId) {
this.contentId = contentId;
this.content = null;
}
async getContent() {
// simulate loading content from a database
await new Promise((resolve) => setTimeout(resolve, 3000));
return `<html><body>Content for page ${this.contentId}</body></html>`;
}
}
class CachedContent {
constructor(content) {
this.content = content;
this.cachedContent = null;
}
async getCachedContent() {
if (!this.cachedContent) {
console.log("Cache miss, fetching content...");
this.cachedContent = await this.content.getContent();
}
console.log("Cache hit, returning content from cache...");
return this.cachedContent;
}
}
// Client
const contentId = 3;
const content = new SomeContent(contentId);
const cachedContent = new CachedContent(content);
console.log("First fetch:");
await cachedContent.getCachedContent();
console.log("Second fetch:");
await cachedContent.getCachedContent();
本文标题为:深入理解JavaScript系列(31):设计模式之代理模式详解
基础教程推荐
- Uncaught RangeError: Maximum call stack size exceeded 错误解决方法 2023-07-09
- uni-app实现数据上拉加载更多功能实例 2022-08-30
- 手机安装GreasyFork油猴js脚本的教程 2023-08-11
- 编写轻量ajax组件01-与webform平台上的各种实现方式比较 2022-10-17
- layui自定义组件根据id获取id内的form值 2023-08-31
- JS触摸事件、手势事件详解 2023-12-01
- js使用swiper实现层叠轮播效果实例代码 2023-12-02
- Ajax商品分类三级联动的简单实现(案例) 2023-01-20
- javascript – 是否可以从内存中的html字符串加载电子webContents? 2023-10-25
- 实现Vue路由切换的监听 2023-10-08