Proxy Pattern

  • Proxy Pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it.

  • proxy acts as an intermediary that implements the same interface as the original object, allowing it to intercept and manage requests to the real object

  • Real-Life Analogy

    • Think of a personal assistant:

      • A busy CEO may not respond to everyone directly.

      • Instead, their assistant takes calls, filters emails, manages the calendar, and only involves the CEO when necessary.

      • The assistant controls access to the CEO while still providing essential services to others.

  • Problem It Solves

    • It solves the problem of uncontrolled or expensive access to an object. For example, consider a scenario where:

      • You have a heavy object like a video player that consumes a lot of resources on initialization.

      • You want to delay its creation until it's actually needed (lazy loading).

      • Or maybe the object resides on a remote server, and you want to add a layer to manage the network communication.

    • The Proxy Pattern allows you to control access, defer initialization, add logging, caching, or security without modifying the original object.

  • Real-Life Coding Example

    • Imagine you're building a feature like a video streaming app (think YouTube or Netflix) where users can download videos.

    • Now, consider this: multiple users might try to download the same video multiple times — or even the same user may repeat the request.

    • In such scenarios, if we go ahead and download the video from the internet every single time, it leads to unnecessary network calls, longer wait times, and wasted bandwidth.

    • Let’s consider a scenario where we want to download a video multiple times, perhaps from different places in the code or by different users. A poor design would look like this:

  • Understanding the Issues

    • There's no caching, so the same video is downloaded again and again even if it’s already available.

    • There's no access control or content filtering — any video URL is downloaded without restrictions.

    • The client directly depends on the RealVideoDownloader, meaning there’s no way to intercept, log, or modify the download behavior without changing core logic.

    • It results in multiple object creations and redundant resource usage.

  • The previous implementation made direct use of the RealVideoDownloader class for every download request, even if the same video was requested multiple times.

  • This meant the system would re-download and reprocess the same video repeatedly, leading to unnecessary network usage and redundant computation.

  • To solve this, we use the Proxy Design Pattern — a structural pattern that provides a placeholder or surrogate for another object to control access to it.

  • Good Design: Using Proxy Pattern

  • How Proxy Pattern Solves the Issue

    • In this example, the proxy (CachedVideoDownloader Class) was used that implements a caching logic that checks if a video has already been downloaded.

    • If so, it simply returns the cached result, saving time and resources.

    • This way, the real object is accessed only when absolutely necessary, while repeated requests are served efficiently through the proxy — resulting in faster response times and optimized performance.

  • When to Use Proxy Pattern?

    • When object creation is expensive, and you want to delay or control its instantiation.

    • When you need to control access to sensitive operations or enforce permission checks.

    • When interacting with remote objects that are costly or slow to fetch.

    • When lazy loading is needed to optimize system performance and resource usage.

  • Types of Proxy

    • At a high level, proxies can be categorized into several types based on the specific purpose they serve:

    • Virtual Proxy

      • Purpose: Controls access to a resource that is expensive to create.

        • Use Case: Commonly used for lazy initialization — where the real object is created only when absolutely necessary.

        • Example: A video downloader app that only fetches and loads the video data when the user hits “Play”.

    • Protection Proxy

      • Purpose: Controls access to an object based on user permissions or roles.

      • Use Case: Useful in systems with multi-level access control, such as admin vs. regular users.

      • Example: In a document editor, only editors can modify content while viewers can only read.

    • Remote Proxy

      • Purpose: Controls access to an object located on a remote server or in a different address space.

      • Use Case: Enables local code to access remote services as if they were local.

      • Example: A Java RMI object or API wrapper that abstracts out network communication.

    • Smart Proxy

      • Purpose: Adds additional behavior when accessing the real object.

      • Use Case: Often used for logging, access counting, or reference counting.

      • Example: Automatically logging every time, a file is accessed or updated.

    • Advantages

      • Performance Optimization: By introducing features like caching or lazy initialization, proxies can significantly reduce resource consumption and improve application performance.

      • Access Control: Proxies act as a gatekeeper, controlling access to sensitive or expensive resources, and ensuring that only authorized users can access them.

      • Lazy Initialization: Proxies delay the creation of costly resources until they are actually needed, optimizing resource usage and startup times.

      • Added Functionality: Without modifying the original object, proxies can add additional behavior such as logging, security checks, or usage tracking.

    • Disadvantages

      • Increased Complexity: Introducing a proxy layer adds more components to the system, which can make the overall design harder to understand and maintain.

      • Potential Delays: The proxy may introduce delays in accessing the actual object, especially when additional logic like permission checks or data fetching is involved.

      • Maintenance Overhead: With extra layers and duplicated interfaces, maintaining proxies alongside real objects can increase the development and debugging effort.

Last updated