Proxy Design Pattern in Java

Introduction

The Proxy Design Pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. This pattern is useful when creating objects is resource-intensive, or when access to the real object needs to be controlled or restricted.

Purpose

The main goal of the Proxy Pattern is to manage access to an object. This can involve delaying the creation of the object until it’s actually needed, adding security checks before access, or logging interactions with the object. Essentially, it allows for additional behavior without modifying the real object’s code.

Common Use Cases

The Proxy Pattern is typically used in the following scenarios:

  • When an object is expensive to create, and it is beneficial to delay its creation until it is actually needed (virtual proxy).
  • When access to an object should be restricted or controlled based on permissions (protection proxy).
  • When an object resides in a different address space or network and needs a representative locally (remote proxy).
  • When extra functionality such as logging, reference counting, or caching is required transparently (smart proxy).

Structure

The Proxy Pattern typically consists of three main components:

  1. A Subject interface that defines the common operations.
  2. A RealSubject class that contains the core logic and actual functionality.
  3. A Proxy class that implements the same interface and controls access to the RealSubject.

Example: Protection Proxy

This example demonstrates how to use a proxy to protect access to a document. Only users with the “ADMIN” role are allowed to open and view the document.

Step 1: Subject Interface

public interface Document {
    void display();
}

Step 2: RealSubject Class

public class RealDocument implements Document {
    private String filename;

    public RealDocument(String filename) {
        this.filename = filename;
        loadFromDisk();
    }

    private void loadFromDisk() {
        System.out.println("Loading document: " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying: " + filename);
    }
}

Step 3: Proxy Class

public class DocumentProxy implements Document {
    private RealDocument realDocument;
    private String filename;
    private String userRole;

    public DocumentProxy(String filename, String userRole) {
        this.filename = filename;
        this.userRole = userRole;
    }

    @Override
    public void display() {
        if ("ADMIN".equals(userRole)) {
            if (realDocument == null) {
                realDocument = new RealDocument(filename);
            }
            realDocument.display();
        } else {
            System.out.println("Access denied: Only ADMIN can view the document.");
        }
    }
}

Step 4: Client Code

public class Main {
    public static void main(String[] args) {
        Document doc1 = new DocumentProxy("secret.pdf", "USER");
        doc1.display();

        System.out.println("---");

        Document doc2 = new DocumentProxy("secret.pdf", "ADMIN");
        doc2.display();
        doc2.display();
    }
}

Output

Access denied: Only ADMIN can view the document.
---
Loading document: secret.pdf
Displaying: secret.pdf
Displaying: secret.pdf

Advantages

The Proxy Pattern provides several advantages. It allows lazy instantiation of objects, which saves system resources. It also enables control over access to the object, helping to enforce security policies. Additionally, proxies can add functionalities like logging or caching without modifying the real object’s code.

Disadvantages

The main drawback of the Proxy Pattern is the added layer of abstraction, which may introduce complexity. In certain cases, using a proxy may lead to performance overhead or confusion if not clearly documented.

Conclusion

The Proxy Design Pattern is a powerful tool in situations where object creation is expensive or where access to an object needs to be managed or extended. It offers a clean, structured way to control and enhance the behavior of real objects without changing their code. In Java, proxies are particularly useful for adding security checks, lazy loading, and access control in real-world applications.

Leave a Reply