沃梦达 / IT编程 / 前端开发 / 正文

深入理解JavaScript系列(31):设计模式之代理模式详解

代理模式是一种结构型模式,其中一个对象充当另一个对象的接口,以控制对该对象的访问。 这种类型的设计模式属于结构模式,它对对象进行组合,以提供新的功能,同时使代码更易于维护。

深入理解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):设计模式之代理模式详解