Proxy Design Pattern in Java with Real-World Example

Learn how to implement the Proxy Design Pattern in Java with practical real-world examples and code samples

Design patterns are reusable solutions to common software design problems. In my previous posts, I’ve covered patterns like Factory Method, Builder, and Chain of Responsibility. Today, I’ll explain the Proxy Pattern, another important Gang of Four (GoF) structural design pattern.

Github link to the example 👉 https://github.com/Prasadct/proxy-pattern

What is the Proxy Pattern?

The Proxy pattern provides a surrogate or placeholder for another object to control access to it. It’s like having a representative who acts on behalf of the real object. This pattern is useful when:

  • You want to control access to an object
  • You need to add functionality when accessing an object
  • You want to delay the creation and initialization of an expensive object until it’s actually needed

Types of Proxies

There are several types of proxies, each serving different purposes:

  1. Virtual Proxy: Creates expensive objects on demand
  2. Protection Proxy: Controls access to the original object’s methods
  3. Remote Proxy: Represents an object that exists in a different address space
  4. Logging Proxy: Keeps a log of method calls to the object
  5. Caching Proxy: Stores results of expensive operations for reuse

Structure of the Proxy Pattern

The Proxy pattern consists of these components:

  • Subject Interface: Defines the common interface for RealSubject and Proxy
  • RealSubject: The real object that the proxy represents
  • Proxy: Maintains a reference to the RealSubject and controls access to it

Here’s a diagram showing the structure:

<<interface>>Subject+operation()RealSubject+operation()Proxy-realSubject: RealSubject+operation()

Real-World Example: API Rate Limiter Proxy

Let’s implement a real-world example of the Proxy pattern: an API rate limiter. This is a common requirement in web applications to prevent abuse and ensure fair usage.

Imagine you have a weather service that provides weather data. Without rate limiting, users could potentially overwhelm your service with requests. A rate limiter proxy can control how many requests a user can make within a given time period.

Step 1: Define the Subject Interface

First, let’s define our subject interface for the weather service:

Step 2: Implement the Real Subject

Next, we’ll implement the actual weather service:

Step 3: Implement the Proxy

Now, let’s create our rate limiter proxy:

Step 4: Client Code Using the Proxy

Here’s how a client would use our rate-limited weather service:

The output would look something like:

Fetching weather data for Bangalore from external API
First request: Temperature: 25°C, Condition: Sunny, Location: Bangalore
Fetching weather data for Mumbai from external API
Second request: Temperature: 25°C, Condition: Sunny, Location: Mumbai
Fetching weather data for Delhi from external API
Third request: Temperature: 25°C, Condition: Sunny, Location: Delhi
Error: Rate limit exceeded. Try again later.

Sequence of Events

Let’s look at a sequence diagram to understand how the Proxy pattern works in our example:

Client
Client
RateLimitedProxy
RateLimitedProxy
RealWeatherService
RealWeatherService
getWeatherData(“Bangalore”)Check rate limitgetWeatherData(“Bangalore”)Return weather dataReturn weather datagetWeatherData(“Mumbai”)Check rate limitgetWeatherData(“Mumbai”)Return weather dataReturn weather datagetWeatherData(“Delhi”)Check rate limitgetWeatherData(“Delhi”)Return weather dataReturn weather datagetWeatherData(“Chennai”)Check rate limit (exceeded)Throw exception
Text is not SVG – cannot display

Another Example: Image Loading Proxy

Another classic example of the Proxy pattern is lazy loading of heavy resources like images. Let’s quickly look at a Virtual Proxy implementation for image loading:

Output:

Images will be loaded on demand...

Displaying first image:
Loading image: image1.jpg
Displaying image: image1.jpg

Displaying first image again:
Displaying image: image1.jpg

Displaying second image:
Loading image: image2.jpg
Displaying image: image2.jpg

When to Use the Proxy Pattern

Use the Proxy pattern when:

  1. You need lazy initialization (Virtual Proxy)
  2. You need access control to an object (Protection Proxy)
  3. You need to add logging, caching, or other functionality when accessing an object
  4. You want to control resources that are expensive to create or use

Advantages of the Proxy Pattern

Separation of Concerns: The proxy handles additional functionality while the real subject focuses on its primary responsibility

Open/Closed Principle: You can introduce new proxies without changing the real subject

Protection: Controls access to the real subject

Improved Performance: Can implement caching or lazy loading to optimize resource usage

Disadvantages of the Proxy Pattern

Increased Complexity: Adds another layer of indirection

Response Time: May increase response time in some cases

Implementation Overhead: Requires creating additional classes

Proxy Pattern vs. Other Patterns

Decorator vs. Proxy: Both wrap an object, but decorators add responsibilities while proxies control access

Adapter vs. Proxy: Adapters change an interface, while proxies keep the same interface

Facade vs. Proxy: Facades simplify a complex system, while proxies control access to objects

Conclusion

The Proxy pattern is a powerful tool for controlling access to objects. It can help you implement various functionalities like lazy loading, caching, access control, and logging without modifying the original object. In our real-world examples, we saw how proxies can be used for rate limiting API calls and lazy loading images.

As with all design patterns, use the Proxy pattern when it clearly solves your specific problem, not just because it’s available. Consider the performance implications and added complexity before implementing this pattern in your code.

Have you used the Proxy pattern in your projects? Share your experiences in the comments below!

4 thoughts on “Proxy Design Pattern in Java with Real-World Example

Leave a Reply to Donald3756 Cancel reply

Your email address will not be published. Required fields are marked *