151
structural object-structural

Proxy

Reference Wikipedia ↗
Proxy — class diagram
Plate 151 class diagram

The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This can be used to add functionality before or after the original object’s method is executed, or to simply delay the creation or access of the expensive object until it’s actually needed. It essentially manages access to an object, allowing for features like security checks, lazy loading, or remote access.

Usage

The Proxy pattern is commonly used in scenarios such as:

  • Remote Proxies: When accessing objects across a network, a proxy can handle the communication and complexities of the remote connection.
  • Virtual Proxies: For objects that are expensive to create (e.g., large images or complex data structures), a proxy can load them on demand.
  • Protection Proxies: Controlling access to an object based on permissions or security constraints. A proxy can decide whether or not a client is allowed to use the original object.
  • Smart References: Adding logging, caching, or other side-effects to object access.
  • Caching: Acting as a cache for an expensive operation, returning cached results if available and only invoking the real object when necessary.

Examples

  • JavaScript Proxies (ES6): JavaScript’s Proxy object provides a meta-programming functionality that allows intercepting fundamental operations on objects, such as getting or setting properties. This is effectively a proxy pattern for controlling object access.

    javascript const target = { message: “Hello” }; const handler = { get: function(target, prop, receiver) { console.log(Property ${prop} accessed); return Reflect.get(target, prop, receiver); }, };

    const proxy = new Proxy(target, handler); console.log(proxy.message); // Logs “Property message accessed” and then “Hello”

  • Hibernate Lazy Loading (Java): In the Hibernate Java ORM framework, relationships between entities are often loaded lazily using proxies. When a related entity is accessed for the first time, Hibernate intercepts the access through a proxy and loads the entity from the database only then. This improves performance by avoiding unnecessary data loading.

    java // Assume ‘Customer’ has a ‘address’ field that is lazily loaded Customer customer = session.get(Customer.class, 1); String street = customer.getAddress().getStreet(); // Address is only loaded when accessed

Specimens

15 implementations
Specimen 151.01 Dart View specimen ↗

The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for scenarios like lazy initialization, access control, or logging. In this Dart example, we have a RealImage which is resource-intensive to load. The ImageProxy acts as a proxy, delaying the loading of the RealImage until it’s actually needed (i.e., when display() is called). This improves initial application startup time. The implementation uses Dart’s class-based OOP and leverages the display() method to trigger the actual image loading. It’s idiomatic Dart due to its clear class definitions and method overriding.

// Subject interface
abstract class Image {
  void display();
}

// Real Subject
class RealImage implements Image {
  final String filename;

  RealImage(this.filename) {
    // Simulate a long loading process
    print('Loading image from $filename...');
    // In a real application, this would actually load the image data.
  }

  @override
  void display() {
    print('Displaying image from $filename.');
  }
}

// Proxy
class ImageProxy implements Image {
  final String filename;
  RealImage? _realImage;

  ImageProxy(this.filename);

  @override
  void display() {
    if (_realImage == null) {
      _realImage = RealImage(filename);
    }
    _realImage!.display();
  }
}

// Client
void main() {
  final imageProxy = ImageProxy('high_resolution_image.jpg');
  imageProxy.display(); // Loads the image on first access
  imageProxy.display(); // Displays from cache
}