Proxy

Author      Ter-Petrosyan Hakob

The Proxy design pattern is a structural pattern. It is one of the simplest patterns to understand and use.

The Gang of Four defines the proxy pattern as:

Provide a surrogate or placeholder for another object to control access to it.

In other words, a proxy acts as a gatekeeper. It sits between a client and a real object. The proxy can:

This helps you protect sensitive actions or manage resource use without changing the real object or the client code.

Class Diagram:

img6

This class diagram illustrates the structure of the Proxy pattern:

Example: Command Executor

Imagine a class that runs system commands. If you give it directly to a client, they could run dangerous commands like rm -rf /. We can use a proxy to prevent that.

CommandExecutor Interface:

public interface CommandExecutor {
    void runCommand(String cmd) throws Exception;
}

Real Command Executor:

public class CommandExecutorImpl implements CommandExecutor {
    @Override
    public void runCommand(String cmd) throws UnauthorizedException, CommandExecutionException {
        // Execute the system command
        Runtime.getRuntime().exec(cmd);
        System.out.println("Executed: '" + cmd + "'");
    }
}

Proxy Class:

public class CommandExecutorProxy implements CommandExecutor {
    private static final String ADMIN_USER = "Gurgen";
    private static final String ADMIN_PWD = "J@urnalD$v";

    private final CommandExecutor executor;
    private final boolean isAdmin;

     public CommandExecutorProxy(String user, String pwd) {
        Objects.requireNonNull(user, "user cannot be null");
        Objects.requireNonNull(pwd,  "pwd cannot be null");

        this.executor = new CommandExecutorImpl();
        this.isAdmin  = ADMIN_USER.equals(user) && ADMIN_PWD.equals(pwd);
    }

    @Override
    public void runCommand(String cmd) throws UnauthorizedException, CommandExecutionException {
        Objects.requireNonNull(cmd, "cmd cannot be null");
        String trimmed = cmd.trim();

        if (!isAdmin && trimmed.startsWith("rm")) {
            throw new UnauthorizedException("Permission denied: non‑admin users cannot execute 'rm' commands.");
        }

        try {
            executor.runCommand(cmd);
        } catch (Exception e) {
            throw new CommandExecutionException("Error executing command: " + trimmed, e);
        }
    }
}

Client Code:

public class ProxyPatternTest {
    public static void main(String[] args) {
        CommandExecutor executor = new CommandExecutorProxy("Gurgen", "wrong_pwd");
        try {
            executor.runCommand("ls -ltr");
            executor.runCommand("rm -rf abc.pdf");
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

In this example:

Sequence Diagram

img7

This sequence diagram shows how the Proxy handles a client request:

Common Uses of Proxy Pattern

Pros&Cons

Pros:

Cons:

Relation to Other Patterns