Proxy Design Pattern in R

1. Definition

The Proxy Design Pattern provides a surrogate or placeholder for another object to control access to it. It acts as an intermediary interface between the client and the target object. There are several types of proxy patterns, such as virtual proxy, protection proxy, and remote proxy.

2. Problem Statement

Imagine you have a large and memory-intensive object, like an image. You want to display a list of images but don't want to load them all into memory at once due to the significant overhead. You only want to load an image when it's actually needed to be viewed.

3. Solution

Implement a proxy for the image. The proxy will act as a stand-in for the real image. It will only load (or allow operations on) the actual image when absolutely necessary.

4. Real-World Use Cases

1. Web browsers use proxies to lazily load images only when they come into view.

2. Remote proxies can represent an object in a different address space, often used in distributed systems.

3. Protection proxies that control access to the original object based on access rights.

5. Implementation Steps

1. Create an interface that both the Real Object and Proxy will implement.

2. Implement the Proxy class to control access to the Real Object.

6. Implementation in R Programming

# Step 1: Interface for RealImage and ProxyImage
Image <- setRefClass("Image", methods = list(
  display = function() {}
))
# Step 2: RealImage class that implements Image
RealImage <- setRefClass("RealImage",
  fields = list(filename = "character"),
  methods = list(
    display = function() {
      paste("Displaying", filename)
    },
    initialize = function(filename) {
      # Simulate loading from disk
      cat(paste("Loading image:", filename, "\n"))
      .self$filename <- filename
    }
  )
)
# ProxyImage class that implements Image
ProxyImage <- setRefClass("ProxyImage",
  fields = list(filename = "character", realImage = "RealImage"),
  methods = list(
    display = function() {
      if (is.null(realImage)) {
        realImage <<- RealImage$new(filename) # Load only when needed
      }
      realImage$display()
    }
  )
)
# Client code
image1 <- ProxyImage$new("test1.jpg")
image2 <- ProxyImage$new("test2.jpg")
output1 <- image1$display()
output2 <- image2$display()

Output:

Loading image: test1.jpg
Displaying test1.jpg
Loading image: test2.jpg
Displaying test2.jpg

Explanation:

1. We created an interface Image that both the RealImage (the memory-intensive object) and the ProxyImage adhere to.

2. The RealImage class, when instantiated, simulates loading the image from the disk. This is to mimic the resource-intensive operation.

3. The ProxyImage will only instantiate and load the RealImage when the display method is called, ensuring that resources are used judiciously.

4. In the client code, although we create two ProxyImages, the real images are only loaded when they are displayed.

7. When to use?

Use the Proxy Pattern when:

1. You want to act as an intermediary for requests to an object to control the access.

2. You want to defer the full cost of creation and initialization of an object until it's really needed.

3. When you need a more sophisticated or versatile reference to an object than a simple pointer.

Proxy pattern provides a placeholder to control and manage access to the original object efficiently.


Comments