"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Padrão de design de proxy

Padrão de design de proxy

Publicado em 2024-11-06
Navegar:546

Proxy Design Pattern

Em meus blogs anteriores, explorei vários padrões de design criativo que lidam com mecanismos de criação de objetos. Agora é hora de mergulhar nos padrões de design estrutural, que se concentram em como objetos e classes são compostos para formar estruturas maiores, mantendo-as flexíveis e eficientes. Vamos começar com o padrão de design de proxy

Padrão de design de proxy em JavaScript

O padrão de design Proxy é um padrão de design estrutural que fornece um objeto que representa outro objeto. Ele atua como um intermediário que controla o acesso ao objeto real, adicionando comportamento adicional, como inicialização lenta, registro em log, controle de acesso ou cache, sem alterar o código do objeto original.

Em JavaScript, proxies são recursos integrados fornecidos pelo objeto Proxy, permitindo definir comportamento personalizado para operações fundamentais, como acesso a propriedades, atribuição, invocação de função, etc.

Quando precisamos do padrão proxy?

O padrão Proxy é particularmente útil quando:

  • Inicialização lenta: Você deseja atrasar a criação de um objeto com muitos recursos até que seja necessário.
  • Controle de acesso: você precisa controlar o acesso a um objeto, por exemplo, para restringir o acesso não autorizado ou para limitar operações com base em condições.
  • Registro: Você deseja registrar ações em um objeto (por exemplo, acesso a propriedades ou chamadas de métodos).
  • Cache: Você deseja armazenar em cache o resultado de operações caras para evitar cálculos redundantes.

Componentes do padrão proxy

  1. Assunto: A interface que define as operações comuns para o objeto real e o proxy.
  2. RealSubject: O objeto real que executa o trabalho real.
  3. Proxy: O intermediário que controla o acesso ao RealSubject.

Analogia:

Imagine que você tem uma pintura grande que deseja mostrar aos seus convidados, mas leva muito tempo para retirá-la de um depósito (porque é pesada e demora para carregar). Em vez de esperar por isso todas as vezes, você decide usar uma pequena imagem de cartão postal da pintura para mostrá-los rapidamente enquanto esperam que a pintura real seja buscada.

Nesta analogia:

  • A pintura grande é o objeto real (como uma imagem que demora para carregar).
  • O cartão postal é o proxy (um substituto leve que permanece até que o objeto real esteja pronto).
  • Quando a pintura real estiver pronta, você mostra a pintura real aos seus convidados.

Analogia do mundo real:

Pense em um corretor de imóveis como um procurador. Quando você quer comprar uma casa, você não visita imediatamente todas as casas (carregando o objeto real). Em vez disso, o agente imobiliário (proxy) mostra primeiro fotos e descrições. Somente quando você estiver pronto para comprar (ou seja, quando você ligar para display()), o agente marcará uma visita domiciliar (carrega o objeto real).

Exemplo do mundo real: carregamento de imagem (proxy virtual)

Vamos usar o exemplo de carregamento de imagem em uma aplicação web onde queremos atrasar o carregamento da imagem até que o usuário solicite (carregamento lento). Um proxy pode atuar como um espaço reservado até que a imagem real seja carregada.

Veja como você pode implementar o padrão de design Proxy em JavaScript.

Exemplo: proxy para carregamento de imagens

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

Explicação:

1). A imagem real:

  • A classe RealImage representa a imagem real.
  • Ele recebe um nome de arquivo como entrada e simula o demorado processo de carregamento da imagem do disco (mostrado pelo método loadImageFromDisk).
  • Depois de carregado, o método display é usado para mostrar a imagem.

2). A imagem proxy:

  • A classe ProxyImage atua como um substituto para o RealImage. Não carrega a imagem real imediatamente.
  • Contém uma referência à imagem real (mas inicialmente é nula porque a imagem real ainda não foi carregada).
  • Quando você chama o método display no proxy, ele verifica se a imagem real foi carregada. Caso contrário, ele carrega primeiro e depois o exibe.

3). Uso:

  • Quando criamos uma instância de ProxyImage, a imagem real ainda não foi carregada (porque consome muitos recursos).
  • Na primeira vez que display é chamado, o proxy carrega a imagem (usando a classe RealImage) e a exibe.
  • Na segunda vez que display é chamado, a imagem real já foi carregada, então ele apenas exibe a imagem sem carregá-la novamente.

O objeto Proxy integrado

O proxy ES6 consiste em um construtor de proxy que aceita um alvo e um manipulador como argumentos

const proxy = new Proxy(target, handler)

Aqui, target representa o objeto no qual o proxy é aplicado, enquanto handler é um objeto especial que define o comportamento do proxy.

O objeto manipulador contém uma série de métodos opcionais com nomes predefinidos chamados métodos trap (por exemplo, apply,get,set e has) que são chamados automaticamente quando as operações correspondentes são executadas na instância do proxy.

Vamos entender isso implementando a calculadora usando 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.
}

A melhor parte de usar proxy desta forma como:

  • O objeto proxy herda o protótipo da classe Calculadora original.
  • Mutações são evitadas através da armadilha definida do Proxy.

Explicação do Código

1). Herança do protótipo:

  • O proxy não interfere no protótipo original da classe **Calculadora **.
  • isso é confirmado verificando se proxiedCalculator.proto === Calculator.prototype. O resultado será verdadeiro.

2). Tratando getOperations:

  • A armadilha get intercepta o acesso à propriedade no objeto proxy.
  • Usamos Reflect.get para acessar com segurança propriedades e métodos do objeto original.

3). Prevenindo mutações:

O set trap gera um erro sempre que há uma tentativa de modificar qualquer propriedade no objeto de destino. Isso garante imutabilidade.

4). Usando métodos de protótipo por meio do proxy:

O proxy permite acesso a métodos como adição, subtração, multiplicação e divisão, todos definidos no protótipo do objeto original.

Os principais pontos a serem observados aqui são:

  • Preserva a herança do protótipo: O proxy retém acesso a todos os métodos do protótipo, fazendo com que ele se comporte como a calculadora original.
  • Previne mutação: O set trap garante que o estado interno do objeto da calculadora não possa ser alterado inesperadamente.
  • Acesso seguro a propriedades e métodos: A armadilha get garante que apenas propriedades válidas sejam acessadas, melhorando a robustez.

Se você chegou até aqui, não se esqueça de clicar em curtir ❤️ e deixar um comentário abaixo com qualquer dúvida ou opinião. Seu feedback significa muito para mim e adoraria ouvir de você!

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/srishtikprasad/proxy-design-pattern-4mm?1 Se houver alguma violação, entre em contato com [email protected] para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3