Understanding the Proxy Design Pattern in Software Development

In software development, there's a common philosophy: many problems can be solved by adding an intermediate layer. The Proxy pattern is a direct application of this concept. The Proxy pattern is defined as: **Provide a surrogate or placeholder for another object to control access to it.** This involves delegating a class to another class that manages access to the original class, such as for permission control. There are two types of proxies: static proxies and dynamic proxies. Let's first examine static proxies.

Static Proxy Pattern


// Interface
public interface Service {
    public void performTask();
    
    public void executeOperation();
}

// Real object
public class RealService implements Service {
    public void performTask(){
        System.out.println("Executing the core task");
    }
    
    public void executeOperation(){
        System.out.println("Performing required operation!");
    }
}

// Proxy class
public class ServiceProxy implements Service{
    private Service service;
    public ServiceProxy(){
        this.service = new RealService();
    }
    
    public void performTask(){
        System.out.println("Preparing for task execution!");
        service.performTask();
    }
    
    public void executeOperation(){
        service.executeOperation();
    }
}

public class Application {
    public static void main(String[] args) {
        Service svc = new ServiceProxy();
        svc.performTask();
        svc.executeOperation();
    }
}

-------------------------------------------------------------------------
Preparing for task execution!
Executing the core task
Performing required operation!

Dynamic Proxy Pattern

The dynamic proxy example utilizes the Service interface and RealService class from the previous example.

// Dynamic proxy
public class DynamicServiceProxy implements InvocationHandler {

    private Service service = null;
    
    public Service getServiceProxy(Service service1){
        this.service = service1;
        Service svc = (Service)Proxy.newProxyInstance(service.getClass().getClassLoader(), 
                                                   service.getClass().getInterfaces(), 
                                                   this);
        return svc;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = null;
        System.out.println("Preparing for method execution!");
        result = method.invoke(service, args);
        
        return result;
    }
    
}

public class Application {
    public static void main(String[] args) {
        DynamicServiceProxy dsp = new DynamicServiceProxy();
        Service realService = dsp.getServiceProxy(new RealService());
        realService.performTask();
        realService.executeOperation();
        
    }
}
-------------------------------------------------------------------------
Preparing for method execution!
Executing the core task
Preparing for method execution!
Performing required operation!

1. In Java, dynamic proxies require implementing the InvocationHandler interface. 2. You must then override the invoke method. The first parameter is the proxy object, the second is the method to be proxied, and the third is the method parameters. Additionally, the invoke method is called automatically and doesn't need explicit invocation by the user. From these examples, we can see that static proxies have a one-to-one relationship between the proxy and the real object. The proxy class needs corresponding methods for each method in the real object, making it inflexible when the real object has many methods. Dynamic proxies solve this problem through Proxy, InvocationHandler, and the invoke method, allowing unified handling of all methods, making them more flexible and convenient. Java's dynamic proxies can only proxy interfaces. If you need to proxy classes, you must use the CGLIB library.

Common Use Cases for the Proxy Pattern

1. Remote Proxy 2. Virtual Proxy 3. Copy-on-Write Proxy 4. Protection (Access Control) Proxy 5. Cache Proxy 6. Firewall Proxy 7. Synchronization Proxy 8. Smart Reference Proxy These typical use cases demonstrate the essence of the Proxy pattern: controlling access to classes.

Distinguishing Proxy Pattern from Decorator Pattern

While their implementations are quite similar, the Proxy pattern focuses on controlling access to classes, whereas the Decorator pattern is primarily for dynamically enhancing functionality.

Tags: Design Patterns Proxy Pattern Software Architecture Java Programming

Posted on Mon, 13 Jul 2026 16:59:18 +0000 by Jeremias