"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Modèle de conception de proxy

Modèle de conception de proxy

Publié le 2024-11-06
Parcourir:435

Proxy Design Pattern

Dans mes blogs précédents, j'ai exploré divers modèles de conception créative qui traitent des mécanismes de création d'objets. Il est maintenant temps de se plonger dans les modèles de conception structurelle, qui se concentrent sur la façon dont les objets et les classes sont composés pour former des structures plus grandes tout en les gardant flexibles et efficaces. Commençons par le modèle de conception de proxy

Modèle de conception de proxy en JavaScript

Le modèle de conception proxy est un modèle de conception structurel qui fournit un objet représentant un autre objet. Il agit comme un intermédiaire qui contrôle l'accès à l'objet réel, en ajoutant des comportements supplémentaires tels qu'une initialisation paresseuse, une journalisation, un contrôle d'accès ou une mise en cache, sans modifier le code de l'objet d'origine.

Dans JavaScript, les proxys sont des fonctionnalités intégrées fournies par l'objet Proxy, vous permettant de définir un comportement personnalisé pour les opérations fondamentales telles que l'accès aux propriétés, l'affectation, l'invocation de fonctions, etc.

Quand avons-nous besoin du modèle de proxy ?

Le modèle Proxy est particulièrement utile lorsque :

  • Initialisation paresseuse : Vous souhaitez retarder la création d'un objet gourmand en ressources jusqu'à ce qu'il soit nécessaire.
  • Contrôle d'accès : vous devez contrôler l'accès à un objet, par exemple, pour restreindre les accès non autorisés ou pour limiter les opérations en fonction de conditions.
  • Journalisation : Vous souhaitez enregistrer les actions sur un objet (par exemple, l'accès à une propriété ou des appels de méthode).
  • Mise en cache : Vous souhaitez mettre en cache le résultat d'opérations coûteuses pour éviter les calculs redondants.

Composants du modèle de proxy

  1. Sujet : L'interface qui définit les opérations communes à la fois pour l'objet réel et le proxy.
  2. RealSubject : L'objet réel qui effectue le travail réel.
  3. Proxy : L'intermédiaire qui contrôle l'accès au RealSubject.

Analogie:

Imaginez que vous ayez un grand tableau que vous souhaitez montrer à vos invités, mais qu'il faut beaucoup de temps pour le sortir d'un débarras (car il est lourd et prend du temps à transporter). Au lieu d'attendre cela à chaque fois, vous décidez d'utiliser une petite image de carte postale du tableau pour leur montrer rapidement pendant qu'ils attendent que le tableau lui-même soit récupéré.

Dans cette analogie :

  • Le grand tableau est l'objet réel (comme une image qui met du temps à se charger).
  • La carte postale est le proxy (un substitut léger qui intervient jusqu'à ce que l'objet réel soit prêt).
  • Une fois le vrai tableau prêt, vous montrez le véritable à vos invités.

Analogie du monde réel :

Considérez un agent immobilier comme un mandataire. Lorsque vous souhaitez acheter une maison, vous ne visitez pas immédiatement chaque maison (chargement de l’objet réel). Au lieu de cela, l’agent immobilier (mandataire) vous montre d’abord des photos et des descriptions. Ce n'est que lorsque vous êtes prêt à acheter (c'est-à-dire lorsque vous appelez display()) que l'agent organise une visite à domicile (charge l'objet réel).

Exemple concret : chargement d'images (proxy virtuel)

Prenons l'exemple du chargement d'une image dans une application web où l'on souhaite retarder le chargement de l'image jusqu'à ce que l'utilisateur le demande (chargement paresseux). Un proxy peut servir d'espace réservé jusqu'à ce que l'image réelle soit chargée.

Voici comment implémenter le modèle de conception Proxy en JavaScript.

Exemple : proxy pour le chargement d'images

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

Explication:

1). L'image réelle :

  • La classe RealImage représente l'image réelle.
  • Il prend un nom de fichier en entrée et simule le processus fastidieux de chargement de l'image à partir du disque (indiqué par la méthode loadImageFromDisk).
  • Une fois chargée, la méthode d'affichage est utilisée pour afficher l'image.

2). L'image proxy :

  • La classe ProxyImage agit comme un remplaçant pour la RealImage. Il ne charge pas immédiatement l’image réelle.
  • Il contient une référence à l'image réelle (mais au départ, elle est nulle car l'image réelle n'a pas encore été chargée).
  • Lorsque vous appelez la méthode d'affichage sur le proxy, elle vérifie si l'image réelle a été chargée. Sinon, il le charge d'abord, puis l'affiche.

3). Usage:

  • Lorsque nous créons une instance de ProxyImage, l'image réelle n'est pas encore chargée (car elle consomme beaucoup de ressources).
  • La première fois que display est appelé, le proxy charge l'image (à l'aide de la classe RealImage) puis l'affiche.
  • La deuxième fois que l'affichage est appelé, l'image réelle a déjà été chargée, il affiche donc uniquement l'image sans la charger à nouveau.

L'objet Proxy intégré

Le proxy ES6 se compose d'un constructeur de proxy qui accepte une cible et un gestionnaire comme arguments

const proxy = new Proxy(target, handler)

Ici, target représente l'objet sur lequel le proxy est appliqué, tandis que handler est un objet spécial qui définit le comportement du proxy.

L'objet gestionnaire contient une série de méthodes facultatives avec des noms prédéfinis appelées méthodes trap (par exemple apply,get,set et has) qui sont automatiquement appelées lorsque les opérations correspondantes sont effectuées sur l'instance de proxy.

Comprenons cela en implémentant la calculatrice à l'aide du proxy intégré

// 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 meilleure partie en utilisant le proxy de cette façon :

  • L'objet proxy hérite du prototype de la classe Calculator d'origine.
  • Les mutations sont évitées grâce au piège posé par le proxy.

Explication du Code

1). Héritage des prototypes :

  • Le proxy n'interfère pas avec le prototype original de la classe **Calculator **.
  • cela est confirmé en vérifiant si proxyedCalculator.proto === Calculator.prototype. Le résultat sera true.

2). Gestion des opérations getOperations :

  • Le piège get intercepte l'accès aux propriétés sur l'objet proxy.
  • Nous utilisons Reflect.get pour accéder en toute sécurité aux propriétés et méthodes de l'objet d'origine.

3). Prévenir les mutations :

Le piège set génère une erreur chaque fois qu'il y a une tentative de modification d'une propriété sur l'objet cible. Cela garantit l'immuabilité.

4). Utilisation de méthodes prototypes via le proxy :

Le proxy permet d'accéder à des méthodes telles que l'addition, la soustraction, la multiplication et la division, qui sont toutes définies sur le prototype de l'objet d'origine.

Les points clés à observer ici sont :

  • Préserve l'héritage du prototype : Le proxy conserve l'accès à toutes les méthodes prototypes, ce qui le fait se comporter comme la calculatrice d'origine.
  • Empêche la mutation : Le piège défini garantit que l'état interne de l'objet calculatrice ne peut pas être modifié de manière inattendue.
  • Accès sécurisé aux propriétés et aux méthodes : Le piège get garantit que seules les propriétés valides sont accessibles, améliorant ainsi la robustesse.

Si vous êtes arrivé jusqu'ici, n'oubliez pas de cliquer sur J'aime ❤️ et de laisser un commentaire ci-dessous si vous avez des questions ou des idées. Vos commentaires comptent énormément pour moi et j'aimerais avoir de vos nouvelles !

Déclaration de sortie Cet article est reproduit sur : https://dev.to/srishtikprasad/proxy-design-pattern-4mm?1 En cas de violation, veuillez contacter [email protected] pour le supprimer.
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3