Proxy Design Pattern in Ruby

1. Definition

The Proxy Design Pattern provides a surrogate or placeholder for another object to control access to it. The primary reason for using a proxy is to act as a controlling intermediary between a client and the real object.

2. Problem Statement

There are situations when we want to add some functionality to an object, but we don't want to modify its structure. This could be for access control, lazy initialization, logging, etc.

3. Solution

The Proxy pattern suggests creating a new proxy class with the same interface as the original object. This proxy class can then wrap the original object, adding additional behaviors and controlling access to it.

4. Real-World Use Cases

1. Lazy loading of a heavyweight object.

2. Access control to resources or operations.

3. Logging access and operations for debugging or auditing purposes.

5. Implementation Steps

1. Define the common interface for both the RealObject and the Proxy.

2. Create the Proxy class that holds a reference to the RealObject.

3. Implement the proxy methods, adding the desired functionality before or after calling the real object's methods.

6. Implementation in Ruby

# Step 1: Common Interface class AbstractObject def request raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end # Step 2: RealObject class RealObject < AbstractObject def request "RealObject: Handling request." end end # Step 3: Proxy Object class ProxyObject < AbstractObject def initialize(real_object) @real_object = real_object end def request # Additional behavior (e.g., logging, access control) if access_granted? @real_object.request + " (handled by Proxy)" else "Proxy: Access denied." end end private def access_granted? # Simulate access control check true end end # Client code proxy = ProxyObject.new(RealObject.new) puts proxy.request 

Output:

RealObject: Handling request. (handled by Proxy) 

Explanation:

1. The AbstractObject class provides a common interface for both RealObject and ProxyObject.

2. RealObject is the actual object that performs the primary function.

3. ProxyObject wraps around RealObject and can control access to it, or add additional functionalities. In this example, it checks access using the access_granted? method and then lets the RealObject handle the request.

4. The client interacts with the ProxyObject, which in turn interacts with the RealObject when appropriate.

7. When to use?

Use the Proxy pattern when:

1. You need a more versatile or sophisticated reference to an object than just a pointer.

2. You want to lazy-initialize your heavy objects only when they're needed.

3. You need to log, monitor, or secure access to the actual object without changing it.


Comments