"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > Patrón de diseño de proxy

Patrón de diseño de proxy

Publicado el 2024-11-06
Navegar:353

Proxy Design Pattern

En mis blogs anteriores, exploré varios patrones de diseño creativo que tratan con mecanismos de creación de objetos. Ahora es el momento de sumergirnos en patrones de diseño estructural, que se centran en cómo se componen los objetos y las clases para formar estructuras más grandes y al mismo tiempo mantenerlas flexibles y eficientes. Comencemos con el patrón de diseño de proxy

Patrón de diseño de proxy en JavaScript

El patrón de diseño Proxy es un patrón de diseño estructural que proporciona un objeto que representa otro objeto. Actúa como un intermediario que controla el acceso al objeto real, añadiendo comportamientos adicionales como inicialización diferida, registro, control de acceso o almacenamiento en caché, sin cambiar el código del objeto original.

En JavaScript, los servidores proxy son funciones integradas proporcionadas por el objeto Proxy, lo que le permite definir un comportamiento personalizado para operaciones fundamentales como acceso a propiedades, asignación, invocación de funciones, etc.

¿Cuándo necesitamos el patrón proxy?

El patrón Proxy es particularmente útil cuando:

  • Inicialización diferida: Desea retrasar la creación de un objeto con muchos recursos hasta que sea necesario.
  • Control de acceso: Necesita controlar el acceso a un objeto, por ejemplo, para restringir el acceso no autorizado o limitar las operaciones según las condiciones.
  • Registro: Desea registrar acciones en un objeto (por ejemplo, acceso a propiedades o llamadas a métodos).
  • Almacenamiento en caché: Desea almacenar en caché el resultado de operaciones costosas para evitar cálculos redundantes.

Componentes del patrón proxy

  1. Asunto: La interfaz que define las operaciones comunes tanto para el objeto real como para el proxy.
  2. RealSubject: El objeto real que realiza el trabajo real.
  3. Proxy: El intermediario que controla el acceso al RealSubject.

Analogía:

Imagina que tienes un cuadro grande que quieres mostrar a tus invitados, pero te lleva mucho tiempo sacarlo de un cuarto de almacenamiento (porque es pesado y toma tiempo transportarlo). En lugar de esperar eso cada vez, decides usar una pequeña imagen postal de la pintura para mostrársela rápidamente mientras esperan que traigan la pintura real.

En esta analogía:

  • La pintura grande es el objeto real (como una imagen que tarda en cargarse).
  • La postal es el proxy (un sustituto ligero que permanece hasta que el objeto real esté listo).
  • Una vez que la pintura real esté lista, muestra la pintura real a tus invitados.

Analogía del mundo real:

Piense en un agente de bienes raíces como un apoderado. Cuando quieres comprar una casa, no visitas todas las casas inmediatamente (cargando el objeto real). En cambio, el agente inmobiliario (representante) primero le muestra fotos y descripciones. Solo cuando esté listo para comprar (es decir, cuando llame a display()), el agente organiza una visita a la casa (carga el objeto real).

Ejemplo del mundo real: carga de imágenes (proxy virtual)

Usemos el ejemplo de carga de imágenes en una aplicación web donde queremos retrasar la carga de la imagen hasta que el usuario la solicite (carga diferida). Un proxy puede actuar como marcador de posición hasta que se carga la imagen real.

A continuación se explica cómo implementar el patrón de diseño Proxy en JavaScript.

Ejemplo: proxy para cargar imágenes

// 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)

Explicación:

1). La imagen real:

  • La clase RealImage representa la imagen real.
  • Toma un nombre de archivo como entrada y simula el lento proceso de cargar la imagen desde el disco (que se muestra mediante el método loadImageFromDiskm).
  • Una vez cargado, el método de visualización se utiliza para mostrar la imagen.

2). La imagen proxy:

  • La clase ProxyImage actúa como sustituto de RealImage. No carga la imagen real inmediatamente.
  • Contiene una referencia a la imagen real (pero inicialmente es nula porque la imagen real aún no se ha cargado).
  • Cuando llamas al método de visualización en el proxy, verifica si se ha cargado la imagen real. Si no, lo carga primero y luego lo muestra.

3). Uso:

  • Cuando creamos una instancia de ProxyImage, la imagen real aún no se carga (porque consume muchos recursos).
  • La primera vez que se llama a display, el proxy carga la imagen (usando la clase RealImage) y luego la muestra.
  • La segunda vez que se llama a la visualización, la imagen real ya se ha cargado, por lo que solo muestra la imagen sin cargarla nuevamente.

El objeto Proxy incorporado

El proxy ES6 consta de un constructor de proxy que acepta un objetivo y un controlador como argumentos

const proxy = new Proxy(target, handler)

Aquí, el objetivo representa el objeto sobre el cual se aplica el proxy, mientras que el controlador es un objeto especial que define el comportamiento del proxy.

El objeto controlador contiene una serie de métodos opcionales con nombres predefinidos llamados métodos trap (por ejemplo, aplicar, obtener, establecer y tiene) que se llaman automáticamente cuando se realizan las operaciones correspondientes en la instancia de proxy.

Entendamos esto implementando la calculadora usando el proxy integrado

// 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.
}

La mejor parte es usar proxy de esta manera:

  • El objeto proxy hereda el prototipo de la clase Calculadora original.
  • Las mutaciones se evitan mediante la trampa del Proxy.

Explicación del Código

1). Herencia del prototipo:

  • El proxy no interfiere con el prototipo original de la clase **Calculadora**.
  • esto se confirma verificando si calculadora proxy.proto === Calculator.prototype. El resultado será verdadero.

2). Manejo de getOperations:

  • La captura get intercepta el acceso a la propiedad en el objeto proxy.
  • Usamos Reflect.get para acceder de forma segura a propiedades y métodos del objeto original.

3). Prevención de mutaciones:

La trampa establecida arroja un error cada vez que se intenta modificar cualquier propiedad en el objeto de destino. Esto garantiza la inmutabilidad.

4). Uso de métodos de prototipo a través del proxy:

El proxy permite el acceso a métodos como sumar, restar, multiplicar y dividir, todos los cuales están definidos en el prototipo del objeto original.

Los puntos clave a observar aquí son:

  • Conserva la herencia del prototipo: El proxy conserva el acceso a todos los métodos del prototipo, lo que hace que se comporte como la Calculadora original.
  • Evita la mutación: La trampa establecida garantiza que el estado interno del objeto de la calculadora no pueda modificarse inesperadamente.
  • Acceso seguro a propiedades y métodos: La trampa get garantiza que solo se acceda a propiedades válidas, lo que mejora la solidez.

Si has llegado hasta aquí, no olvides darle a Me gusta ❤️ y dejar un comentario a continuación con cualquier pregunta o idea. ¡Tus comentarios significan mucho para mí y me encantaría saber de ti!

Declaración de liberación Este artículo se reproduce en: https://dev.to/srishtikprasad/proxy-design-pattern-4mm?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarla.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3