Introducció al Patró Proxy

El patró Proxy és un patró estructural que proporciona un substitut o un representant d'un altre objecte per controlar l'accés a aquest. Aquest patró és útil quan necessitem controlar l'accés a un objecte, afegir funcionalitats addicionals abans o després de l'accés a l'objecte, o retardar la creació d'un objecte costós fins que sigui necessari.

Objectius del Patró Proxy

  • Controlar l'accés: Permet controlar l'accés a l'objecte original.
  • Reduir el cost: Retarda la creació de l'objecte fins que sigui necessari.
  • Afegir funcionalitats: Permet afegir funcionalitats addicionals abans o després de l'accés a l'objecte.

Tipus de Proxies

  1. Remote Proxy: Controla l'accés a un objecte que resideix en un espai d'adreces diferent.
  2. Virtual Proxy: Retarda la creació d'un objecte costós fins que sigui necessari.
  3. Protection Proxy: Controla l'accés a un objecte basat en permisos.
  4. Smart Proxy: Proporciona funcionalitats addicionals com la referència comptada o la verificació de bloqueig.

Diagrama UML del Patró Proxy

+-----------------+          +-----------------+
|     Client      |          | RealSubject     |
+-----------------+          +-----------------+
| - subject: Proxy|<>------->| + request()     |
+-----------------+          +-----------------+
        |                        ^
        |                        |
        v                        |
+-----------------+              |
|     Proxy       |--------------+
+-----------------+
| - realSubject:  |
|   RealSubject   |
+-----------------+
| + request()     |
+-----------------+

Implementació del Patró Proxy

Exemples de Codi

Interface Subject

public interface Subject {
    void request();
}

Classe RealSubject

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

Classe Proxy

public class Proxy implements Subject {
    private RealSubject realSubject;

    @Override
    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        System.out.println("Proxy: Logging the request.");
        realSubject.request();
    }
}

Classe Client

public class Client {
    public static void main(String[] args) {
        Subject proxy = new Proxy();
        proxy.request();
    }
}

Explicació del Codi

  1. Subject Interface: Defineix la interfície comuna per a RealSubject i Proxy.
  2. RealSubject: Implementa la interfície Subject i conté la lògica real que es vol controlar.
  3. Proxy: També implementa la interfície Subject i conté una referència a RealSubject. Controla l'accés a RealSubject i pot afegir funcionalitats addicionals.
  4. Client: Utilitza l'objecte Proxy per accedir a RealSubject.

Exercici Pràctic

Enunciat

Implementa un patró Proxy que controli l'accés a un objecte BankAccount. El proxy ha de verificar si l'usuari té permisos per accedir al compte bancari abans de permetre qualsevol operació.

Solució

Interface BankAccount

public interface BankAccount {
    void deposit(double amount);
    void withdraw(double amount);
    double getBalance();
}

Classe RealBankAccount

public class RealBankAccount implements BankAccount {
    private double balance;

    @Override
    public void deposit(double amount) {
        balance += amount;
        System.out.println("Deposited " + amount + ". New balance: " + balance);
    }

    @Override
    public void withdraw(double amount) {
        if (amount <= balance) {
            balance -= amount;
            System.out.println("Withdrew " + amount + ". New balance: " + balance);
        } else {
            System.out.println("Insufficient funds.");
        }
    }

    @Override
    public double getBalance() {
        return balance;
    }
}

Classe BankAccountProxy

public class BankAccountProxy implements BankAccount {
    private RealBankAccount realBankAccount;
    private String userRole;

    public BankAccountProxy(String userRole) {
        this.userRole = userRole;
        this.realBankAccount = new RealBankAccount();
    }

    private boolean hasAccess() {
        return "ADMIN".equals(userRole);
    }

    @Override
    public void deposit(double amount) {
        if (hasAccess()) {
            realBankAccount.deposit(amount);
        } else {
            System.out.println("Access denied. Only ADMIN can deposit.");
        }
    }

    @Override
    public void withdraw(double amount) {
        if (hasAccess()) {
            realBankAccount.withdraw(amount);
        } else {
            System.out.println("Access denied. Only ADMIN can withdraw.");
        }
    }

    @Override
    public double getBalance() {
        if (hasAccess()) {
            return realBankAccount.getBalance();
        } else {
            System.out.println("Access denied. Only ADMIN can view the balance.");
            return 0;
        }
    }
}

Classe Client

public class Client {
    public static void main(String[] args) {
        BankAccount adminAccount = new BankAccountProxy("ADMIN");
        adminAccount.deposit(100);
        adminAccount.withdraw(50);
        System.out.println("Balance: " + adminAccount.getBalance());

        BankAccount userAccount = new BankAccountProxy("USER");
        userAccount.deposit(100);
        userAccount.withdraw(50);
        System.out.println("Balance: " + userAccount.getBalance());
    }
}

Explicació del Codi

  1. BankAccount Interface: Defineix les operacions que es poden realitzar en un compte bancari.
  2. RealBankAccount: Implementa la interfície BankAccount i conté la lògica real per gestionar el compte bancari.
  3. BankAccountProxy: Implementa la interfície BankAccount i controla l'accés a RealBankAccount basat en el rol de l'usuari.
  4. Client: Utilitza l'objecte BankAccountProxy per accedir a RealBankAccount.

Resum

El patró Proxy és una eina poderosa per controlar l'accés a un objecte, afegir funcionalitats addicionals i retardar la creació d'objectes costosos. Hem vist com implementar aquest patró amb un exemple pràctic de control d'accés a un compte bancari. Aquest patró és especialment útil en situacions on es necessita un control estricte sobre l'accés a certs recursos o funcionalitats.

© Copyright 2024. Tots els drets reservats