Skip to main content

Command Palette

Search for a command to run...

Week 12 - Structural Design Pattern: Proxy

Design Patterns Demystified Series

Published
4 min read
Week 12 - Structural Design Pattern: Proxy

Welcome back to our Design Patterns Demystified series!
After exploring memory optimization with the Flyweight Pattern, this week we move into another powerful structural pattern — the Proxy Pattern

This pattern is all about control: controlling access, behavior, or cost when interacting with an object. Let’s break it down the simple way — with a library analogy and clean Java code.

🧠 What Is the Proxy Pattern?

The Proxy Pattern provides a substitute or placeholder for another object to control access to it.

Instead of interacting with the real object directly, the client talks to a proxy, which decides:

  • Whether access is allowed

  • When to create the real object

  • Whether to add extra behavior (logging, security, caching, etc.)

The client doesn’t know (or care) whether it’s talking to the real object or a proxy.

📚 Real-World Analogy: College Library Access Desk

Imagine a college library system.

  • Students want to issue books

  • The Library Database handles the actual issuing

  • But not every student is allowed to issue books

So instead of letting students directly access the database, they go through a Library Access Desk (Proxy)

The proxy:

  • Verifies whether the student is authorized

  • Grants access if valid

  • Denies access if not

This is exactly what the Proxy Pattern does.


💻 Let’s Translate That Into Code

  1. Subject Interface — Library.java
package com.designpatterns.structuralpatterns.proxy;

// Subject Interface
public interface Library {
    void issueBook(String studentName, String bookTitle);
}

This interface is shared by:

  • The real object

  • The proxy

2. Real Object — LibraryDatabase.java

package com.designpatterns.structuralpatterns.proxy;

public class LibraryDatabase implements Library {
    @Override
    public void issueBook(String studentName, String bookTitle) {
        System.out.println("Book '" + bookTitle + "' issued to " + studentName);
    }
}

This class performs the actual work — issuing books.

3. Proxy — LibraryProxy.java

package com.designpatterns.structuralpatterns.proxy;

// Proxy
class LibraryProxy implements Library {
    private LibraryDatabase libraryDatabase;
    private java.util.Set<String> authorizedStudents;
    public LibraryProxy() {
        libraryDatabase = new LibraryDatabase();
        authorizedStudents = new java.util.HashSet<>();
        authorizedStudents.add("Alice");
        authorizedStudents.add("Bob");
    }
    @Override
    public void issueBook(String studentName, String bookTitle) {
        if (authorizedStudents.contains(studentName)) {
            System.out.println("Access granted for " + studentName);
            libraryDatabase.issueBook(studentName, bookTitle);
        } else {
            System.out.println("Access denied for " + studentName + ". Not authorized to issue books.");
        }
    }
}

🔍 What the proxy does here:

  • Checks authorization

  • Controls access to the real database

  • Delegates the request only if allowed

4. Client — ProxyPatternDemo.java

package com.designpatterns.structuralpatterns.proxy;

// Client
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Library library = new LibraryProxy();
        library.issueBook("Alice", "Design Patterns");
        library.issueBook("Charlie", "Java Programming");
    }
}

5. Output

Access granted for Alice
Book 'Design Patterns' issued to Alice
Access denied for Charlie. Not authorized to issue books.

🎯 What This Demonstrates

  • The client interacts with the proxy, not the real object

  • The proxy controls who can access the real service

  • The real object remains unchanged and unaware

  • Additional logic (security) is added without modifying the real class

This is the core power of the Proxy Pattern.


🧩 Why Use the Proxy Pattern?

Advantages

  • Adds security and access control

  • Avoids unnecessary object creation

  • Keeps real objects clean and focused

  • Follows the Open/Closed Principle

  • Improves performance and flexibility

When to Use It

  • When you need controlled access to an object

  • When object creation is expensive

  • When you want to add behavior without modifying existing code

  • When security, logging, or lazy loading is required

🌍 Real-World Use Cases

  • Authentication & authorization systems

  • Database connection pooling

  • API gateways

  • Virtual proxies for large files (images, videos)

  • Caching layers

  • Remote service access (RMI, REST clients)

🔜 Next Up: Behavioral Design Pattern — Chain of Responsibility

Next week, we’ll explore how the Chain of Responsibility Pattern helps you pass requests through a chain of handlers — allowing multiple objects to process a request without tightly coupling them.

Stay tuned as we break it down with beginner-friendly code examples, relatable analogies, and real-world use cases. We’ll help you write cleaner, more flexible, and more maintainable code — one pattern at a time.

✅ Call to Action (CTA)

🚀 Want to level up your design pattern skills?
Subscribe or follow the series — we’ll walk through each pattern with examples, analogies, and real-world code you can use today.


Note: AI-generated image

Design Patterns

Part 13 of 25

Let’s be honest—most devs would rather code than study design patterns. They seem academic and full of jargon. But this guide is different: plain language, real-life analogies, and practical examples that make your code smarter, cleaner, and scalable

Up next

Week 13 - Behavioral Design Pattern: Chain of Responsibility

Design Patterns Demystified Series