The Proxy pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. This pattern is particularly useful for adding a layer of control over how and when an object is accessed.

If you need to execute something before or after the primary logic of the class, the proxy lets you do this without changing that class. Since the proxy implements the same interface as the original class, it can be passed to any client that expects a real service object.

Structure

The Proxy pattern consists of the following key components:

  • Subject: is an interface defining common operations for Proxy and Concrete Subject so that the Proxy can be substituted in place of the Subject
  • Concrete Subject: is an implementation for the Subject interface
  • Proxy: object maintains a reference to the Concrete Subject and controls access to it and can perform some operations before and after calling the object function
  • Client: uses Concrete Subjects and Proxy using the Subject interface

When to use the Proxy Pattern?

  • When you want to control and restrict access to objects
  • When you want to log and monitor operations performed on an object
  • When you want to validate inputs before passing them to the actual object

Implementation Example

The code below demonstrates the implementation of the Proxy design pattern in Java.

This code implements the Proxy design pattern to control access to a document based on user roles. The SecureDocumentProxy class acts as a protective layer around the RealDocument, implementing the Document interface. It checks user permissions before allowing view or edit operations. The Solution class demonstrates the usage, creating proxy objects for both a user and an admin, then attempting to view and edit the document with each role. The proxy allows both roles to view the document but restricts editing to the admin role only, illustrating how the pattern can be used for access control in object-oriented design.

// Client class
public class Solution {
    
    public static void main(String[] args) {
        
        Document userDocument = new SecureDocumentProxy("Confidential contents of the Document", "USER");
        Document adminDocument = new SecureDocumentProxy("Confidential contents of the Document", "ADMIN");

        System.out.println("User attempting to view confidential document:");
        userDocument.view();
        System.out.println("\nUser attempting to edit confidential document:");
        userDocument.edit();

        System.out.println("\nAdmin attempting to view confidential document:");
        adminDocument.view();
        System.out.println("\nAdmin attempting to edit confidential document:");
        adminDocument.edit();

    }
}

// Subject interface
interface Document {

    void view();
    void edit();
}

// Concrete Subject
class RealDocument implements Document {

    private String content;

    public RealDocument(String content) {

        this.content = content;
    }

    public void view() {

        System.out.println("Viewing document: " + content);
    }

    public void edit() {

        System.out.println("Editing document: " + content);
    }
}

// Proxy class
class SecureDocumentProxy implements Document {

    private RealDocument realDocument;
    private String userRole;

    public SecureDocumentProxy(String content, String userRole) {

        this.realDocument = new RealDocument(content);
        this.userRole = userRole;
    }

    public void view() {

        if (hasViewPermission()) {

            realDocument.view();
        } else {

            System.out.println("Access denied: You don't have permission to view this document.");
        }
    }

    public void edit() {

        if (hasEditPermission()) {

            realDocument.edit();
        } else {

            System.out.println("Access denied: You don't have permission to edit this document.");
        }
    }

    private boolean hasViewPermission() {

        return userRole.equals("USER") || userRole.equals("ADMIN");
    }

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

The output of the following program will be:

User attempting to view confidential document:
Viewing document: Confidential contents of the Document

User attempting to edit confidential document:
Access denied: You don't have permission to edit this document.

Admin attempting to view confidential document:
Viewing document: Confidential contents of the Document

Admin attempting to edit confidential document:
Editing document: Confidential contents of the Document