Bird
Raised Fist0
LLDsystem_design~15 mins

Proxy pattern in LLD - Deep Dive

Choose your learning style10 modes available
Overview - Proxy pattern
What is it?
The Proxy pattern is a design approach where one object controls access to another object. It acts like a middleman or a placeholder that manages requests before they reach the real object. This helps add extra behavior like security, caching, or lazy loading without changing the original object. It is useful when direct access to an object is expensive or needs control.
Why it matters
Without the Proxy pattern, systems would have to expose objects directly, risking security, inefficiency, or complexity. For example, without a proxy, every request might hit a slow database directly, causing delays. Proxies help improve performance, add security checks, and simplify complex interactions, making software more reliable and easier to maintain.
Where it fits
Before learning the Proxy pattern, you should understand basic object-oriented programming concepts like classes and interfaces. After mastering proxies, you can explore related patterns like Decorator and Adapter, and advanced topics like caching strategies and access control in distributed systems.
Mental Model
Core Idea
A proxy is a stand-in object that controls access to another object, adding extra behavior without changing the original.
Think of it like...
Imagine a receptionist at an office who answers calls and decides which calls to forward to the boss. The receptionist is the proxy controlling access to the boss.
┌─────────────┐       ┌─────────────┐
│   Client    │──────▶│   Proxy     │──────▶
└─────────────┘       └─────────────┘
                             │
                             ▼
                      ┌─────────────┐
                      │ Real Object │
                      └─────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding direct object access
🤔
Concept: Learn how clients normally interact directly with objects.
In simple programs, a client calls methods on an object directly. For example, a client calls a method to fetch data from a database object. This direct access is straightforward but can cause problems if the object is slow or needs protection.
Result
Clients can use objects easily but have no control over how or when the object works.
Understanding direct access shows why sometimes we need a middleman to add control or extra features.
2
FoundationIntroducing the proxy as a middleman
🤔
Concept: The proxy stands between the client and the real object to control access.
Instead of calling the real object directly, the client calls the proxy. The proxy then decides whether to forward the request, block it, or add extra steps like logging or caching.
Result
Clients interact with the proxy just like the real object, but the proxy can add behavior transparently.
Seeing the proxy as a middleman helps understand how it can add features without changing the real object.
3
IntermediateTypes of proxies and their uses
🤔Before reading on: do you think all proxies do the same job or have different purposes? Commit to your answer.
Concept: Proxies come in different types like virtual, protection, and caching proxies, each solving specific problems.
A virtual proxy delays creating expensive objects until needed. A protection proxy checks permissions before forwarding requests. A caching proxy stores results to avoid repeated work. Each type uses the proxy concept but for different goals.
Result
You can choose the right proxy type based on the problem you want to solve.
Knowing proxy types helps apply the pattern effectively in real systems.
4
IntermediateProxy interface and implementation details
🤔Before reading on: do you think the proxy must have the exact same interface as the real object? Commit to your answer.
Concept: The proxy implements the same interface as the real object to be interchangeable.
By sharing the same interface, the proxy can be used anywhere the real object is expected. This allows clients to remain unaware of the proxy's presence. The proxy forwards calls to the real object after adding its behavior.
Result
Clients can switch between proxy and real object without code changes.
Understanding interface sharing is key to seamless proxy integration.
5
IntermediateLazy initialization with virtual proxies
🤔
Concept: Virtual proxies create the real object only when needed to save resources.
Sometimes creating an object is costly. A virtual proxy holds a placeholder and creates the real object only when a method is called. This delays expensive operations until absolutely necessary.
Result
Programs use less memory and start faster by avoiding early object creation.
Knowing lazy initialization helps optimize resource use in large systems.
6
AdvancedSecurity enforcement with protection proxies
🤔Before reading on: do you think proxies can prevent unauthorized access or just monitor it? Commit to your answer.
Concept: Protection proxies check user permissions before allowing access to the real object.
A protection proxy intercepts calls and verifies if the client has rights to perform the action. If not, it blocks the request or raises an error. This adds a security layer without changing the real object.
Result
Systems become safer by controlling who can use sensitive objects.
Understanding protection proxies shows how design patterns help enforce security policies.
7
ExpertProxy pattern in distributed systems
🤔Before reading on: do you think proxies only work inside one program or can they work across networks? Commit to your answer.
Concept: In distributed systems, proxies represent remote objects locally, handling communication details.
Remote proxies act as local representatives for objects on other machines. They handle network communication, data serialization, and error handling, making remote calls appear local to clients.
Result
Distributed systems become easier to use and maintain by hiding network complexity.
Knowing remote proxies reveals how the pattern scales beyond single programs to networks.
Under the Hood
The proxy holds a reference to the real object and implements the same interface. When a client calls a method, the proxy intercepts it, performs additional tasks like checking permissions or caching, then forwards the call to the real object if needed. This forwarding can be synchronous or asynchronous depending on the proxy type. The proxy can also delay creating the real object until the first call, saving resources.
Why designed this way?
The Proxy pattern was designed to separate concerns: letting clients use objects without worrying about extra behaviors like security or performance. It avoids changing the real object's code, promoting reuse and flexibility. Alternatives like subclassing would mix concerns and reduce maintainability. The proxy approach keeps responsibilities clear and allows adding features transparently.
┌─────────────┐       ┌─────────────┐       ┌─────────────┐
│   Client    │──────▶│   Proxy     │──────▶│ Real Object │
│             │       │ (controls   │       │ (does real  │
│             │       │  access)    │       │  work)      │
└─────────────┘       └─────────────┘       └─────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does a proxy always improve performance? Commit to yes or no.
Common Belief:A proxy always makes the system faster by adding caching or lazy loading.
Tap to reveal reality
Reality:Proxies can add overhead by adding extra steps or checks, sometimes slowing down calls.
Why it matters:Assuming proxies always improve speed can lead to poor design choices and unexpected slowdowns.
Quick: Is a proxy the same as a decorator? Commit to yes or no.
Common Belief:Proxy and decorator patterns are the same because both wrap objects.
Tap to reveal reality
Reality:Proxies control access and manage object creation or security, while decorators add new behaviors without changing access.
Why it matters:Confusing these patterns can cause misuse and harder-to-maintain code.
Quick: Can a proxy replace the real object completely? Commit to yes or no.
Common Belief:A proxy can do everything the real object does, so the real object is not needed.
Tap to reveal reality
Reality:A proxy delegates actual work to the real object; it cannot replace its core functionality.
Why it matters:Expecting proxies to replace real objects leads to bloated proxies and broken designs.
Quick: Do proxies always require the same interface as the real object? Commit to yes or no.
Common Belief:Proxies can have different interfaces from the real object.
Tap to reveal reality
Reality:Proxies must implement the same interface to be interchangeable with the real object.
Why it matters:Ignoring interface matching breaks client code and defeats the purpose of proxies.
Expert Zone
1
Some proxies combine multiple roles, like caching and security, which can complicate design and testing.
2
Lazy initialization proxies must handle multi-threading carefully to avoid creating multiple real objects.
3
In distributed systems, proxies must manage network failures gracefully, adding complexity beyond local proxies.
When NOT to use
Avoid proxies when the added layer causes unacceptable latency or complexity, such as in high-frequency trading systems. Instead, use direct access with optimized objects or specialized caching layers.
Production Patterns
In real systems, proxies are used for database connection pooling, remote procedure calls (RPC), and access control in microservices. They often integrate with logging and monitoring tools to track usage and performance.
Connections
Decorator pattern
Related pattern that also wraps objects but focuses on adding behavior rather than controlling access.
Understanding proxies clarifies when to use decorators for behavior extension versus proxies for access control.
Firewall in network security
Both act as gatekeepers controlling access to resources based on rules.
Seeing proxies like firewalls helps grasp their role in protecting and managing access in software.
Administrative assistants in organizations
Proxies and assistants both manage requests and filter what reaches the main person or system.
Recognizing this connection shows how proxy patterns mirror real-world delegation and control.
Common Pitfalls
#1Creating a proxy that does too much work itself instead of delegating.
Wrong approach:class Proxy { doWork() { // Does all work here console.log('Doing work in proxy'); } }
Correct approach:class Proxy { constructor(realObject) { this.realObject = realObject; } doWork() { // Adds control, then delegates console.log('Proxy control'); this.realObject.doWork(); } }
Root cause:Misunderstanding that proxies should delegate core tasks to the real object.
#2Not implementing the same interface as the real object.
Wrong approach:class Proxy { differentMethod() { // Proxy method not matching real object } }
Correct approach:class Proxy { doWork() { // Matches real object's method } }
Root cause:Failing to ensure interface compatibility breaks client expectations.
#3Creating the real object too early in a virtual proxy.
Wrong approach:class VirtualProxy { constructor() { this.realObject = new RealObject(); // Created immediately } }
Correct approach:class VirtualProxy { constructor() { this.realObject = null; } doWork() { if (!this.realObject) { this.realObject = new RealObject(); } this.realObject.doWork(); } }
Root cause:Not delaying object creation defeats the purpose of lazy initialization.
Key Takeaways
The Proxy pattern uses a stand-in object to control access to another object, adding features like security, caching, or lazy loading.
Proxies share the same interface as the real object, making them interchangeable and transparent to clients.
Different proxy types solve different problems: virtual proxies delay object creation, protection proxies enforce security, and remote proxies handle network communication.
Misusing proxies by mixing responsibilities or breaking interface contracts leads to fragile and hard-to-maintain code.
In complex systems, proxies help manage resource use, improve security, and simplify distributed communication by hiding complexity.

Practice

(1/5)
1.

What is the main purpose of the Proxy pattern in system design?

easy
A. To replace the real object permanently with a new one
B. To control access to an object by using a placeholder
C. To directly modify the real object's data
D. To create multiple instances of an object

Solution

  1. Step 1: Understand the Proxy pattern role

    The Proxy pattern acts as a stand-in or placeholder to control access to another object.
  2. Step 2: Compare options with the pattern definition

    Only To control access to an object by using a placeholder correctly describes controlling access using a placeholder, which matches the Proxy pattern.
  3. Final Answer:

    To control access to an object by using a placeholder -> Option B
  4. Quick Check:

    Proxy pattern = control access placeholder [OK]
Hint: Proxy controls access via placeholder, not object creation [OK]
Common Mistakes:
  • Confusing Proxy with Singleton pattern
  • Thinking Proxy modifies the real object directly
  • Assuming Proxy replaces the real object permanently
2.

Which of the following is the correct way to declare a proxy class that implements the same interface as the real object?

interface Image {
    void display();
}

// Which proxy class declaration is correct?
easy
A. interface ImageProxy implements Image { void display(); }
B. class ImageProxy extends Image { void display() { /* control access */ } }
C. class ImageProxy { void display() { /* control access */ } }
D. class ImageProxy implements Image { void display() { /* control access */ } }

Solution

  1. Step 1: Recall interface implementation syntax

    In many languages, a class implements an interface using the 'implements' keyword, not 'extends'.
  2. Step 2: Check each option's correctness

    class ImageProxy implements Image { void display() { /* control access */ } } correctly declares a class implementing the interface. class ImageProxy extends Image { void display() { /* control access */ } } wrongly uses 'extends' for an interface. class ImageProxy { void display() { /* control access */ } } misses interface implementation. interface ImageProxy implements Image { void display(); } wrongly declares an interface implementing another interface.
  3. Final Answer:

    class ImageProxy implements Image { void display() { /* control access */ } } -> Option D
  4. Quick Check:

    Proxy class implements interface = class ImageProxy implements Image { void display() { /* control access */ } } [OK]
Hint: Proxy class must implement interface, not extend it [OK]
Common Mistakes:
  • Using 'extends' instead of 'implements' for interfaces
  • Not implementing the interface at all
  • Declaring proxy as an interface instead of a class
3.

Given the following code snippet, what will be the output?

class RealImage {
    void display() { System.out.println("Displaying real image"); }
}

class ProxyImage {
    RealImage realImage;
    void display() {
        if (realImage == null) {
            realImage = new RealImage();
        }
        realImage.display();
    }
}

ProxyImage proxy = new ProxyImage();
proxy.display();
proxy.display();
medium
A. Displaying real image Displaying real image
B. Displaying real image
C. No output
D. NullPointerException

Solution

  1. Step 1: Analyze the first call to display()

    Since realImage is null initially, it is created and then display() prints "Displaying real image".
  2. Step 2: Analyze the second call to display()

    realImage is no longer null, so display() is called directly again, printing the same message.
  3. Final Answer:

    Displaying real image Displaying real image -> Option A
  4. Quick Check:

    Lazy loading calls display twice [OK]
Hint: Proxy lazy loads real object, so display prints twice [OK]
Common Mistakes:
  • Assuming display prints only once
  • Expecting NullPointerException due to uninitialized realImage
  • Thinking proxy suppresses output
4.

Identify the error in the following proxy implementation and select the fix:

class Proxy {
    RealObject real;
    void request() {
        real.request();
    }
}
medium
A. Remove the proxy and call RealObject directly
B. Change method name from request() to execute()
C. Initialize 'real' before calling request()
D. Make 'real' a static variable

Solution

  1. Step 1: Identify the problem in the code

    The proxy calls real.request() but 'real' is never initialized, causing a NullPointerException.
  2. Step 2: Determine the correct fix

    Initializing 'real' before calling request() ensures the real object exists and avoids errors.
  3. Final Answer:

    Initialize 'real' before calling request() -> Option C
  4. Quick Check:

    Uninitialized real causes error; initialize it [OK]
Hint: Always initialize real object before proxy calls it [OK]
Common Mistakes:
  • Ignoring null initialization error
  • Changing method names unnecessarily
  • Removing proxy defeats pattern purpose
5.

You are designing a system where loading a large image file is expensive. You want to use the Proxy pattern to improve performance by loading the image only when needed. Which of the following design choices best applies the Proxy pattern for this scenario?

hard
A. Create a proxy class that holds the image filename and loads the real image only when display() is called
B. Load the real image immediately when the proxy is created to avoid delays
C. Use a proxy that duplicates the image data to speed up access
D. Replace the real image with a smaller thumbnail permanently

Solution

  1. Step 1: Understand the problem context

    Loading large images is expensive, so delaying loading until necessary improves performance.
  2. Step 2: Match design choices to Proxy pattern benefits

    Create a proxy class that holds the image filename and loads the real image only when display() is called uses lazy loading by deferring real image loading until display() is called, which fits Proxy pattern use.
  3. Final Answer:

    Create a proxy class that holds the image filename and loads the real image only when display() is called -> Option A
  4. Quick Check:

    Lazy loading with proxy = Create a proxy class that holds the image filename and loads the real image only when display() is called [OK]
Hint: Proxy delays expensive load until needed (lazy loading) [OK]
Common Mistakes:
  • Loading real object immediately defeats proxy benefit
  • Duplicating data wastes resources
  • Replacing with thumbnail changes object behavior
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard