«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Шаблон проектирования прокси

Шаблон проектирования прокси

Опубликовано 6 ноября 2024 г.
Просматривать:654

Proxy Design Pattern

В своих предыдущих блогах я исследовал различные шаблоны творческого проектирования, связанные с механизмами создания объектов. Теперь пришло время углубиться в паттерны структурного проектирования, которые фокусируются на том, как объекты и классы компонуются для формирования более крупных структур, сохраняя при этом их гибкость и эффективность. Начнем с шаблона проектирования прокси

Шаблон проектирования прокси в JavaScript

Шаблон проектирования «Прокси» — это структурный шаблон проектирования, который предоставляет объект, представляющий другой объект. Он действует как посредник, который контролирует доступ к реальному объекту, добавляя дополнительное поведение, такое как отложенная инициализация, ведение журнала, контроль доступа или кэширование, без изменения кода исходного объекта.

В JavaScript прокси — это встроенные функции, предоставляемые объектом Proxy, которые позволяют вам определять собственное поведение для основных операций, таких как доступ к свойствам, назначение, вызов функций и т. д.

Когда нам нужен шаблон прокси?

Шаблон «Прокси» особенно полезен, когда:

  • Ленивая инициализация: Вы хотите отложить создание ресурсоемкого объекта до тех пор, пока он не понадобится.
  • Контроль доступа: вам необходимо контролировать доступ к объекту, например, ограничивать несанкционированный доступ или ограничивать операции в зависимости от условий.
  • Журналирование: Вы хотите регистрировать действия над объектом (например, доступ к свойству или вызовы методов).
  • Кэширование: Вы хотите кэшировать результаты дорогостоящих операций, чтобы избежать избыточных вычислений.

Компоненты шаблона прокси

  1. Тема: Интерфейс, определяющий общие операции как для реального объекта, так и для прокси.
  2. RealSubject: Фактический объект, выполняющий реальную работу.
  3. Прокси: Посредник, контролирующий доступ к RealSubject.

Аналогия:

Представьте, что у вас есть большая картина, которую вы хотите показать своим гостям, но ее вытаскивание из кладовой занимает много времени (потому что она тяжелая и ее переноска требует времени). Вместо того, чтобы каждый раз ждать этого, вы решаете использовать небольшое изображение картины на открытке, чтобы быстро показать им, пока они ждут, пока принесут настоящую картину.

В этой аналогии:

  • Большая картина — это настоящий объект (например, изображение, загрузка которого требует времени).
  • Открытка — это прокси (легкая замена, которая остается до тех пор, пока реальный объект не будет готов).
  • Как только настоящая картина будет готова, вы покажете ее гостям.

Реальная аналогия:

Думайте об агенте по недвижимости как о доверенном лице. Когда вы хотите купить дом, вы не посещаете сразу каждый дом (загружая реальный объект). Вместо этого агент по недвижимости (прокси) сначала показывает вам фотографии и описания. Только когда вы готовы совершить покупку (т. е. когда вы вызываете display()), агент организует посещение дома (загружает реальный объект).

Пример из реальной жизни: загрузка изображения (виртуальный прокси)

Давайте воспользуемся примером загрузки изображения в веб-приложении, где мы хотим отложить загрузку изображения до тех пор, пока пользователь не запросит его (отложенная загрузка). Прокси-сервер может выступать в качестве заполнителя до тех пор, пока не будет загружено настоящее изображение.

Вот как можно реализовать шаблон проектирования «Прокси» в JavaScript.

Пример: прокси для загрузки изображений

// Step 1: The real object
class RealImage {
  constructor(filename) {
    this.filename = filename;
    this.loadImageFromDisk();
  }

  loadImageFromDisk() {
    console.log(`Loading ${this.filename} from disk...`);
  }

  display() {
    console.log(`Displaying ${this.filename}`);
  }
}

// Step 2: The proxy object
class ProxyImage {
  constructor(filename) {
    this.realImage = null; // no real image yet
    this.filename = filename;
  }

  display() {
    if (this.realImage === null) {
      // load the real image only when needed
      this.realImage = new RealImage(this.filename);
    }
    this.realImage.display(); // display the real image
  }
}

// Step 3: Using the proxy to display the image
const image = new ProxyImage("photo.jpg");
image.display(); // Loads and displays the image
image.display(); // Just displays the image (already loaded)

Объяснение:

1). Реальное изображение:

  • Класс RealImage представляет фактическое изображение.
  • Он принимает имя файла в качестве входных данных и имитирует трудоемкий процесс загрузки изображения с диска (показан методом loadImageFromDisk).
  • После загрузки метод display используется для отображения изображения.

2). Прокси-изображение:

  • Класс ProxyImage действует как замена RealImage. Реальное изображение загружается не сразу.
  • Он содержит ссылку на реальное изображение (но изначально она равна нулю, поскольку настоящее изображение еще не загружено).
  • Когда вы вызываете метод display на прокси, он проверяет, загружено ли настоящее изображение. Если нет, он сначала загружает его, а затем отображает.

3). Использование:

  • Когда мы создаем экземпляр ProxyImage, фактическое изображение еще не загружается (поскольку оно требует больших ресурсов).
  • При первом вызове display прокси-сервер загружает изображение (используя класс RealImage), а затем отображает его.
  • При втором вызове display реальное изображение уже загружено, поэтому оно только отображает изображение, не загружая его повторно.

Встроенный прокси-объект

Прокси-сервер ES6 состоит из конструктора прокси, который принимает цель и обработчик в качестве аргументов

const proxy = new Proxy(target, handler)

Здесь target представляет собой объект, к которому применяется прокси, а обработчик – это специальный объект, определяющий поведение прокси.

Объект-обработчик содержит ряд дополнительных методов с предопределенными именами, называемыми методами-ловушками (например, apply,get,set и has), которые автоматически вызываются при выполнении соответствующих операций над экземпляром прокси.

Давайте разберемся в этом, реализовав калькулятор с использованием встроенного прокси

// Step 1: Define the Calculator class with prototype methods
class Calculator {
  constructor() {
    this.result = 0;
  }

  // Prototype method to add numbers
  add(a, b) {
    this.result = a   b;
    return this.result;
  }

  // Prototype method to subtract numbers
  subtract(a, b) {
    this.result = a - b;
    return this.result;
  }

  // Prototype method to multiply numbers
  multiply(a, b) {
    this.result = a * b;
    return this.result;
  }

  // Prototype method to divide numbers
  divide(a, b) {
    if (b === 0) throw new Error("Division by zero is not allowed.");
    this.result = a / b;
    return this.result;
  }
}

// Step 2: Create a proxy handler to intercept operations
const handler = {
  // Intercept 'get' operations to ensure access to prototype methods
  get(target, prop, receiver) {
    if (prop in target) {
      console.log(`Accessing property: ${prop}`);
      return Reflect.get(target, prop, receiver); // Access property safely
    } else {
      throw new Error(`Property "${prop}" does not exist.`);
    }
  },

  // Intercept 'set' operations to prevent mutation
  set(target, prop, value) {
    throw new Error(`Cannot modify property "${prop}". The calculator is immutable.`);
  }
};

// Step 3: Create a proxy instance that inherits the Calculator prototype
const calculator = new Calculator(); // Original calculator object
const proxiedCalculator = new Proxy(calculator, handler); // Proxy wrapping the calculator

// Step 4: Use the proxy instance
try {
  console.log(proxiedCalculator.add(5, 3)); // Output: 8
  console.log(proxiedCalculator.multiply(4, 2)); // Output: 8
  console.log(proxiedCalculator.divide(10, 2)); // Output: 5

  // Attempt to access prototype directly through proxy
  console.log(proxiedCalculator.__proto__ === Calculator.prototype); // Output: true

  // Attempt to modify a property (should throw an error)
  proxiedCalculator.result = 100; // Error: Cannot modify property "result".
} catch (error) {
  console.error(error.message); // Output: Cannot modify property "result". The calculator is immutable.
}

Лучшая часть использования прокси:

  • Прокси-объект наследует прототип исходного класса Calculator.
  • Мутаций можно избежать благодаря установленной ловушке Прокси.

Пояснение Кодекса

1). Наследование прототипа:

  • Прокси-сервер не мешает исходному прототипу класса **Калькулятор**.
  • это подтверждается проверкой, если proxiedCalculator.proto === Calculator.prototype. Результатом будет истина.

2). Обработка getOperations:

  • Ловушка get перехватывает доступ к свойствам прокси-объекта.
  • Мы используем Reflect.get для безопасного доступа к свойствам и методам исходного объекта.

3). Предотвращение мутаций:

Ловушка set выдает ошибку при каждой попытке изменить какое-либо свойство целевого объекта. Это обеспечивает неизменность.

4). Использование методов прототипа через прокси:

Прокси обеспечивает доступ к таким методам, как сложение, вычитание, умножение и деление, все из которых определены в прототипе исходного объекта.

Ключевые моменты, на которые следует обратить внимание:

  • Сохраняет наследование прототипа: Прокси сохраняет доступ ко всем методам прототипа, благодаря чему он ведет себя как исходный калькулятор.
  • Предотвращает мутацию: Установленная ловушка гарантирует, что внутреннее состояние объекта калькулятора не может быть неожиданно изменено.
  • Безопасный доступ к свойствам и методам: Ловушка get обеспечивает доступ только к допустимым свойствам, что повышает надежность.

Если вы зашли так далеко, не забудьте поставить лайк ❤️ и оставить комментарий ниже с любыми вопросами или мыслями. Ваш отзыв очень важен для меня, и мне бы хотелось услышать ваше мнение!

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/srishtikprasad/proxy-design-pattern-4mm?1. Если есть какие-либо нарушения, свяжитесь с [email protected], чтобы удалить ее.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3