Bird
Raised Fist0

Proxy Pattern - Access Control, Lazy Loading, Caching Proxy

LLDeasyInterview freq: medium
Choose your preparation mode4 modes available
๐ŸŽฏ
Proxy Pattern - Access Control, Lazy Loading, Caching Proxy
40 min ยท medium
medium

Design a system where clients access a resource-intensive service through a proxy that controls access based on user roles, lazily initializes the real service object, and caches results to reduce repeated expensive calls.

  • There are multiple user roles (e.g., ADMIN, GUEST) with different access permissions.
  • The real service object is expensive to create and should be lazily loaded.
  • The proxy caches results of service calls to improve performance.
  • Access control must prevent unauthorized method calls at runtime.
  • The system must be thread-safe to handle concurrent client requests.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define the Subject Interface
Design the common interface that both the RealSubject and Proxy will implement. What methods should it expose?
๐Ÿ’ก Hint
Use a Java interface to define the contract without holding state. This allows both RealSubject and Proxy to be interchangeable.
Use a Java interface Subject with method signatures only, since interfaces cannot hold instance state in Java.
Mid: Names the Proxy pattern and interface usage. Senior: Explains interface cannot hold state, enabling polymorphism and substitutability.
โš ๏ธCommon Wrong Answer
Using an abstract class for Subject with no shared state leads to unnecessary complexity and violates interface segregation.
Step 2
Implement RealSubject with Expensive Initialization
Implement the RealSubject class that performs expensive initialization. How do you ensure it is only created when needed?
๐Ÿ’ก Hint
Use lazy initialization with a private constructor and create the instance only when first requested by the Proxy.
RealSubject is a concrete class with expensive constructor; lazy loading deferred to Proxy to avoid premature instantiation.
Mid: Identifies lazy loading concept. Senior: Explains why RealSubject constructor is not called until Proxy triggers it, avoiding unnecessary resource usage.
โš ๏ธCommon Wrong Answer
Instantiating RealSubject eagerly in Proxy constructor wastes resources and defeats lazy loading purpose.
Step 3
Design Proxy with Access Control and Lazy Loading
Design the Proxy class that controls access based on user roles and lazily initializes RealSubject. How do you enforce thread-safe lazy loading?
๐Ÿ’ก Hint
Use a volatile RealSubject reference and double-checked locking with synchronized block to ensure safe lazy initialization in Java.
Declare RealSubject instance volatile in Proxy; use synchronized block with double-checked locking to safely initialize RealSubject exactly once.
Mid: Names Proxy pattern and access control. Senior: Traces thread interleaving where without volatile, Thread 2 may see partially constructed RealSubject, causing runtime errors.
โš ๏ธCommon Wrong Answer
Lazy initialization without volatile leads to visibility issues; threads may see null or partially constructed RealSubject causing NullPointerException.
Step 4
Implement Caching in Proxy
Add caching to Proxy to store results of expensive method calls. How do you ensure cache consistency and thread safety?
๐Ÿ’ก Hint
Use a thread-safe concurrent map (e.g., ConcurrentHashMap) to store cached results, avoiding explicit synchronization for reads.
Use java.util.concurrent.ConcurrentHashMap for cache storage in Proxy to allow concurrent reads/writes without explicit synchronization.
Mid: Recognizes caching improves performance. Senior: Explains how ConcurrentHashMap avoids race conditions and stale data without blocking all threads.
โš ๏ธCommon Wrong Answer
Using HashMap without synchronization causes race conditions leading to corrupted cache and inconsistent results.
Step 5
Enforce Access Control Based on User Roles
How does Proxy enforce access control for different user roles at runtime? How to prevent unauthorized method calls?
๐Ÿ’ก Hint
Store user role in Proxy; check role before forwarding calls to RealSubject. Throw SecurityException if unauthorized.
Proxy stores userRole as final field; methods check userRole before delegating, throwing SecurityException if access denied.
Mid: Describes role-based access control in Proxy. Senior: Explains how final userRole ensures thread-safe immutable state and prevents race conditions on role checks.
โš ๏ธCommon Wrong Answer
Not checking user role or using mutable userRole without synchronization allows unauthorized access or race conditions.
๐Ÿ”Œ
API Design Challenge
Design the API for the Proxy Pattern system that supports access control, lazy loading, and caching. How should the interface and classes be structured to allow extensibility and thread safety?
  • Define a Subject interface with method signatures that both RealSubject and Proxy implement.
  • Use a volatile reference and double-checked locking in Proxy for thread-safe lazy initialization.
  • Use a thread-safe cache like ConcurrentHashMap to store method call results.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • Subject interface with method signatures only
  • RealSubject with expensive constructor and no eager instantiation
  • Proxy with volatile RealSubject and synchronized double-checked locking
  • Proxy caching using ConcurrentHashMap for thread-safe cache
  • Access control enforced via final userRole field and runtime checks
Good to Have - 30%
  • Throwing SecurityException on unauthorized access
  • Explanation of volatile visibility guarantees
  • Use of final fields for safe publication
  • Clear separation of concerns following SOLID principles
Bonus - 10%
  • Detailed thread interleaving explanation for lazy loading race condition
  • Use of Java concurrency utilities beyond synchronized and volatile
Using HashMap without synchronization leads to corrupted cache and inconsistent results at runtime
Lazy initialization without volatile causes visibility issues and partially constructed objects
Mutable userRole field without synchronization causes race conditions and unauthorized access
Eager instantiation of RealSubject defeats lazy loading and wastes resources
Using abstract class for Subject without shared state violates interface segregation and adds unnecessary complexity
โœ…
Model Answer
โ–ผ Reveal

The design uses a Subject interface to define the service contract. RealSubject implements this interface and performs expensive initialization deferred until first use. Proxy implements Subject and holds a volatile reference to RealSubject, lazily initializing it with double-checked locking to ensure thread safety. Proxy caches method results in a ConcurrentHashMap to improve performance and stores a final userRole field to enforce access control. Unauthorized access attempts result in SecurityException being thrown.

  • Use of Java interface for Subject to enable polymorphism and substitutability
  • Lazy initialization of RealSubject deferred to Proxy using volatile and double-checked locking for thread safety
  • ConcurrentHashMap used for caching to avoid synchronization overhead and race conditions
  • Final userRole field ensures thread-safe immutable access control checks
  • Throw SecurityException on unauthorized access to prevent security breaches
  • Subject interface defines service methods without state, enabling polymorphism.
  • RealSubject is a concrete class with expensive constructor; lazy loading deferred to Proxy.
  • Proxy holds volatile RealSubject reference; uses double-checked locking with synchronized block for thread-safe lazy initialization.
  • Proxy caches results in ConcurrentHashMap to allow concurrent access without explicit synchronization.
  • Proxy stores final userRole field to enforce immutable, thread-safe access control checks.
  • Proxy throws SecurityException on unauthorized access attempts to prevent security breaches.
  • Use of volatile ensures visibility of RealSubject instance across threads after initialization.
  • ConcurrentHashMap avoids race conditions and deadlocks common with synchronized HashMap.
  • Final fields guarantee safe publication of userRole to all threads without synchronization.
  • Proxy pattern enforces Single Responsibility Principle by separating access control, caching, and lazy loading.

Practice

(1/5)
1. In the Elevator System, should the Elevator class implement an interface or extend an abstract class to represent different elevator types (e.g., passenger, freight)? Consider that elevators share common state and behavior but also have type-specific logic.
easy
A. Use an abstract class, because elevators share common state and partial behavior implementations.
B. Use an interface, because elevators only share behavior signatures, not state.
C. Use a concrete class, because inheritance is unnecessary for elevator types.
D. Use multiple interfaces, one per behavior, to avoid state duplication.

Solution

  1. Step 1: Analyze shared state and behavior

    Elevators share common fields like currentFloor, direction, and doorStatus, plus some implemented methods.
  2. Step 2: Abstract class fits shared state and partial behavior

    Abstract class allows code reuse and enforces common state, while subclasses override type-specific logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Abstract class supports shared state and behavior [check]
Hint: Abstract class for shared state; interface for pure behavior [check]
Common Mistakes:
2. In a parking system, should Vehicle be an abstract class or an interface if it needs to hold state like licensePlate and provide default behavior for getSize()? Why?
easy
A. Interface, because Java 8+ interfaces can have default methods and static fields
B. Interface, because it allows multiple inheritance and enforces method contracts without state
C. Abstract class, because it can hold state and provide default method implementations
D. Abstract class, because it forces subclasses to implement all methods without defaults

Solution

  1. Step 1: Analyze state and behavior requirements

    Since Vehicle needs to hold state like licensePlate and provide default behavior, it requires fields and method implementations.
  2. Step 2: Abstract class vs interface capabilities

    Abstract classes can have instance fields and concrete methods, while interfaces cannot hold instance state (only constants) and default methods cannot manage instance variables.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    State + default behavior -> abstract class, not interface [check]
Hint: State needs abstract class; interfaces lack instance fields [check]
Common Mistakes:
3. A class has a private constructor and a static synchronized getInstance() method returning a single instance. Which pattern is applied and why is this the CORRECT use case?
easy
A. Factory Method pattern, because it controls object creation with a static method.
B. Singleton pattern, ensuring only one instance exists with thread-safe lazy initialization.
C. Builder pattern, to construct complex objects step-by-step with controlled instantiation.
D. Prototype pattern, to clone existing instances instead of creating new ones.

Solution

  1. Step 1: Identify the pattern by constructor and method signature

    The private constructor prevents external instantiation, and the static synchronized getInstance() method returns a single shared instance, matching Singleton semantics.
  2. Step 2: Explain why Singleton is correct here

    Singleton ensures a single instance with thread-safe lazy initialization via synchronization, which fits the described code. Factory Method and Builder patterns do not restrict instance count, and Prototype involves cloning, not single instance control.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Private constructor + synchronized static getInstance() -> Singleton pattern [check]
Hint: Private constructor + static synchronized getInstance() -> Singleton [check]
Common Mistakes:
4. The vending machine currently applies a flat pricing strategy. To add a WeekendFeeStrategy that charges extra on weekends, which minimal change respects SOLID principles?
medium
A. Create a new WeekendFeeStrategy class implementing PricingStrategy and inject it without modifying existing classes.
B. Modify the existing PricingStrategy class to add weekend fee logic inside its calculatePrice() method.
C. Add a boolean isWeekend flag to Product and adjust price accordingly.
D. Add conditional logic for weekend fees in the vending machine's dispense() method.

Solution

  1. Step 1: Identify the SOLID principle involved

    The Open-Closed Principle (OCP) requires classes to be open for extension but closed for modification.
  2. Step 2: Evaluate options against OCP

    Create a new WeekendFeeStrategy class implementing PricingStrategy and inject it without modifying existing classes. adds a new strategy class without modifying existing code, respecting OCP. Others modify existing classes or mix concerns.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class extends pricing without modifying existing code [check]
Hint: OCP: extend pricing via new class, don't modify existing [check]
Common Mistakes:
5. Adding a WeekendFeeStrategy to the current parking fee system requires which minimum change to comply with SOLID principles?
medium
A. Add a boolean flag isWeekend in ParkingLot and conditionally apply fees inside existing strategies.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy without modifying existing classes.
C. Modify the existing FeeStrategy interface to add a isWeekend() method and update all implementations.
D. Combine all fee strategies into one class with conditional logic for weekends.

Solution

  1. Step 1: Identify applicable SOLID principle

    The Open/Closed Principle (OCP) requires that classes be open for extension but closed for modification.
  2. Step 2: Evaluate options against OCP

    Create a new WeekendFeeStrategy class implementing FeeStrategy without modifying existing classes. respects OCP by adding a new class without modifying existing ones. Add a boolean flag isWeekend in ParkingLot and conditionally apply fees inside existing strategies. violates OCP by modifying ParkingLot and existing strategies with conditional logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class added, existing code unchanged -> OCP respected [check]
Hint: Add new strategy class, don't modify existing ones [check]
Common Mistakes:
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