Proxy
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
Proxyobject 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 implementationsThe 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
}
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for scenarios like remote access, security checks, or lazy initialization. Here, we have a RealImage that’s expensive to create. The ImageProxy acts as a stand-in, only loading the RealImage when display() is called. This delays the potentially costly operation until it’s actually needed. The Scala implementation leverages immutability and the lazy val keyword for efficient lazy initialization, fitting the functional style often preferred in Scala. The display method is the key interaction point, triggering the real image loading if it hasn’t happened yet.
trait Image {
def display(): Unit
}
class RealImage(private val filename: String) extends Image {
println(s"Loading image from $filename...")
Thread.sleep(2000) // Simulate a long loading time
def display(): Unit = println(s"Displaying image from $filename.")
}
class ImageProxy(private val filename: String) extends Image {
private val realImage: RealImage = new RealImage(filename) // Create the real image only when needed
def display(): Unit = {
realImage.display()
}
}
object ProxyExample {
def main(args: Array[String]): Unit = {
val imageProxy = new ImageProxy("high_resolution_image.jpg")
imageProxy.display() // This will trigger the loading of the RealImage
imageProxy.display() // Subsequent calls will use the already loaded image
}
}
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 PHP example, we proxy access to a resource-intensive RealSubject (a database connection) through a ProxySubject. The proxy delays the connection until it’s actually needed (lazy initialization) and can potentially add logging or security checks in a real-world scenario. This implementation utilizes PHP’s object-oriented features, defining interfaces for both the subject and the real subject, and then implementing the proxy class to manage access. It’s idiomatic PHP due to its use of interfaces for loose coupling and class-based structure.
<?php
/**
* Interface for the Subject. Both RealSubject and ProxySubject implement this.
*/
interface SubjectInterface
{
public function request();
}
/**
* The RealSubject class. This is the actual object that does the work.
*/
class RealSubject implements SubjectInterface
{
private $data;
public function __construct()
{
// Simulate a resource-intensive operation (e.g., database connection)
echo "RealSubject: Initializing expensive resource...\n";
sleep(2); // Simulate delay
$this->data = "Real Data";
}
public function request()
{
echo "RealSubject: Handling request.\n";
return $this->data;
}
}
/**
* The ProxySubject class. Controls access to the RealSubject.
*/
class ProxySubject implements SubjectInterface
{
private $realSubject = null;
public function request()
{
if ($this->realSubject === null) {
$this->realSubject = new RealSubject();
}
return $this->realSubject->request();
}
}
/**
* Usage example
*/
$proxy = new ProxySubject();
echo "Client: First request...\n";
$proxy->request();
echo "\nClient: Second request (should be faster)...\n";
$proxy->request();
?>
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for scenarios like remote access, security checks, or lazy loading. Here, we have a Book class representing a resource and a BookProxy that intercepts requests to the Book. The proxy handles loading the book’s content only when it’s first accessed (lazy loading) and can potentially add logging or access control in a real-world scenario. This implementation is idiomatic Ruby due to its use of method missing (method_missing) for dynamic dispatch and the principle of “Don’t Repeat Yourself” by delegating to the real subject when available.
# frozen_string_literal: true
# Subject (Real Object)
class Book
def initialize(title, content)
@title = title
@content = content
puts "Loading book: #{@title}" # Simulate loading time
end
def read
@content
end
end
# Proxy
class BookProxy
def initialize(title)
@title = title
@book = nil
end
def read
@book ||= Book.new(@title, "This is the content of #{@title}.")
@book.read
end
def method_missing(method_name, *args)
if @book.nil?
puts "Accessing method '#{method_name}' before book is loaded."
else
@book.send(method_name, *args)
end
end
end
# Client
proxy = BookProxy.new("The Ruby Way")
puts proxy.read
puts proxy.read # Content is cached, no reloading
# proxy.some_other_method # Demonstrates method_missing
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for adding security, logging, or other cross-cutting concerns without modifying the original object. The proxy has the same interface as the real object, allowing clients to interact with it transparently.
Here, Subject defines the interface. RealSubject is the actual object with the resource. Proxy acts as the intermediary, controlling access to RealSubject. The Proxy checks a condition (e.g., authentication) before delegating to the RealSubject. This implementation uses Swift’s protocol-oriented programming, defining the Subject as a protocol and conforming to it with concrete types. This is a common and idiomatic approach in Swift for achieving polymorphism and defining interfaces.
// Define the Subject interface
protocol Subject {
func request()
}
// The RealSubject class
class RealSubject: Subject {
func request() {
print("RealSubject: Handling request.")
}
}
// The Proxy class
class Proxy: Subject {
private var realSubject: RealSubject?
init() {
// Potentially lazy load the real subject
}
private func createRealSubject() {
realSubject = RealSubject()
}
func request() {
if realSubject == nil {
createRealSubject()
}
// Add some logic here - e.g., check permissions, log access
print("Proxy: Checking access before firing real request.")
realSubject?.request()
}
}
// Client code
let proxy = Proxy()
proxy.request()
proxy.request() // Demonstrates potential lazy loading
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. It’s useful for adding functionality like access control, lazy initialization, or logging without modifying the original object. This Kotlin example uses an interface for the real subject (RealImage) and a proxy (ImageProxy) that handles loading the image only when it’s needed. The proxy also includes a simple access control mechanism (checking if the user is authorized). This implementation leverages Kotlin’s concise syntax, interface delegation, and the lazy keyword for efficient resource handling, fitting well with the language’s functional and object-oriented capabilities.
// Subject interface
interface Image {
fun display()
}
// Real Subject
class RealImage(private val filename: String) : Image {
override fun display() {
println("Displaying $filename")
}
}
// Proxy
class ImageProxy(private val filename: String, private val user: String) : Image {
private var realImage: RealImage? = null
override fun display() {
if (user == "admin") {
if (realImage == null) {
realImage = RealImage(filename)
}
realImage?.display()
} else {
println("Access denied for user $user")
}
}
}
// Client
fun main() {
val image1 = ImageProxy("image1.jpg", "admin")
val image2 = ImageProxy("image2.jpg", "guest")
image1.display() // Displays image1.jpg
image2.display() // Access denied
image1.display() // Displays image1.jpg (already loaded)
}
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 Rust example, we have a Subject trait representing the real object, a RealSubject implementing that trait, and a Proxy that holds a reference to the RealSubject. The Proxy intercepts calls to the do_something method. It lazily creates the RealSubject only when needed and then delegates the call. This implementation leverages Rust’s ownership and borrowing system for safe and efficient proxying, avoiding unnecessary cloning and ensuring the RealSubject is only instantiated once. The use of Option<Box<dyn Subject>> within the Proxy is idiomatic for handling potentially uninitialized resources.
trait Subject {
fn do_something(&self);
}
struct RealSubject {
data: String,
}
impl RealSubject {
fn new(data: String) {
println!("RealSubject created with data: {}", data);
}
}
impl Subject for RealSubject {
fn do_something(&self) {
println!("RealSubject doing something with data: {}", self.data);
}
}
struct Proxy {
real_subject: Option<Box<dyn Subject>>,
data: String,
}
impl Proxy {
fn new(data: String) -> Self {
Proxy {
real_subject: None,
data,
}
}
fn get_real_subject(&mut self) -> &mut Box<dyn Subject> {
self.real_subject.insert(Box::new(RealSubject::new(self.data.clone())))
}
}
impl Subject for Proxy {
fn do_something(&self) {
let real_subject = self.real_subject.as_ref().unwrap();
real_subject.do_something();
}
}
fn main() {
let proxy = Proxy::new("Important Data".to_string());
println!("First call to do_something:");
proxy.do_something();
println!("Second call to do_something:");
proxy.do_something();
}
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for adding functionality like access control, lazy initialization, or logging without modifying the original object. In this Go example, we have a RealImage that loads and displays an image. The ProxyImage acts as a proxy, deferring the image loading until Display() is called. This demonstrates lazy loading. The implementation uses interfaces to decouple the proxy from the real subject, a common practice in Go for achieving flexibility and testability. The Display() method on the proxy checks if the image is already loaded; if not, it loads it and then displays it.
// image.go
// Image is the interface that both RealImage and ProxyImage implement.
type Image interface {
Display()
}
// RealImage represents the actual image loading and display logic.
type RealImage struct {
filePath string
}
// NewRealImage creates a new RealImage instance.
func NewRealImage(filePath string) *RealImage {
return &RealImage{filePath: filePath}
}
// Display loads and displays the image.
func (i *RealImage) Display() {
println("Loading image from:", i.filePath)
// Simulate image loading delay
// time.Sleep(2 * time.Second)
println("Displaying image.")
}
// ProxyImage is the proxy that controls access to the RealImage.
type ProxyImage struct {
realImage *RealImage
filePath string
}
// NewProxyImage creates a new ProxyImage instance.
func NewProxyImage(filePath string) *ProxyImage {
return &ProxyImage{filePath: filePath}
}
// Display displays the image, loading it if necessary.
func (p *ProxyImage) Display() {
if p.realImage == nil {
p.realImage = NewRealImage(p.filePath)
}
p.realImage.Display()
}
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for scenarios like remote access, security checks, or lazy initialization. Here, we proxy a File object with a FileProxy that handles file opening and reads. The FileProxy checks if the file is already open; if not, it opens it and stores the File pointer for subsequent use. This avoids repeatedly opening the file, improving performance. The implementation uses C’s pointer-based approach to manage the underlying File object and demonstrates encapsulation through function pointers. It’s a common pattern in C, leveraging its ability to work directly with memory addresses.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Interface for the real object (File)
typedef struct File {
char *filename;
int data;
int isOpen;
} File;
File *file_create(const char *filename) {
File *f = (File *)malloc(sizeof(File));
if (f) {
f->filename = strdup(filename);
f->data = 0;
f->isOpen = 0;
}
return f;
}
void file_open(File *file) {
printf("Opening file: %s\n", file->filename);
file->isOpen = 1;
// Simulate reading data from the file
file->data = 42;
}
int file_read(File *file) {
if (file->isOpen) {
printf("Reading from file: %s\n", file->filename);
return file->data;
} else {
printf("File is not open.\n");
return -1;
}
}
void file_close(File *file) {
printf("Closing file: %s\n", file->filename);
file->isOpen = 0;
}
void file_destroy(File *file) {
if (file) {
free(file->filename);
free(file);
}
}
// Proxy interface
typedef struct FileProxy {
File *realFile;
char *filename;
} FileProxy;
FileProxy *file_proxy_create(const char *filename) {
FileProxy *proxy = (FileProxy *)malloc(sizeof(FileProxy));
if (proxy) {
proxy->realFile = NULL;
proxy->filename = strdup(filename);
}
return proxy;
}
void file_proxy_open(FileProxy *proxy) {
if (proxy->realFile == NULL) {
proxy->realFile = file_create(proxy->filename);
file_open(proxy->realFile);
} else {
printf("File already open.\n");
}
}
int file_proxy_read(FileProxy *proxy) {
if (proxy->realFile == NULL) {
printf("File not opened yet.\n");
return -1;
}
return file_read(proxy->realFile);
}
void file_proxy_close(FileProxy *proxy) {
if (proxy->realFile != NULL) {
file_close(proxy->realFile);
file_destroy(proxy->realFile);
proxy->realFile = NULL;
}
}
void file_proxy_destroy(FileProxy *proxy) {
if (proxy) {
free(proxy->filename);
free(proxy);
}
}
int main() {
FileProxy *proxy = file_proxy_create("my_file.txt");
file_proxy_read(proxy); // File not opened yet.
file_proxy_open(proxy);
int data = file_proxy_read(proxy);
printf("Data read: %d\n", data);
file_proxy_open(proxy); // File already open.
file_proxy_close(proxy);
file_proxy_read(proxy); // File not opened yet.
file_proxy_destroy(proxy);
return 0;
}
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for scenarios like remote access, security checks, or lazy initialization. The Subject interface defines the common access point, the RealSubject is the actual object of interaction, and the Proxy controls access to the RealSubject.
This C++ implementation uses smart pointers (std::shared_ptr) to manage the lifetime of the RealSubject within the Proxy. The Proxy intercepts requests and performs actions (like logging or access control) before forwarding them to the RealSubject. Using interfaces (std::enable_shared_from_this) allows the RealSubject to be safely shared through the Proxy. This approach is idiomatic C++ due to its emphasis on resource management and the use of RAII principles.
#include <iostream>
#include <memory>
#include <string>
// Forward declaration
class RealSubject;
// Subject interface
class Subject {
public:
virtual ~Subject() = default;
virtual void request() = 0;
};
// RealSubject
class RealSubject : public std::enable_shared_from_this<RealSubject> {
public:
void request() {
std::cout << "RealSubject: Handling request." << std::endl;
}
};
// Proxy
class Proxy : public Subject {
public:
Proxy(std::shared_ptr<RealSubject> realSubject) : realSubject_(realSubject) {}
void request() override {
std::cout << "Proxy: Logging the request before forwarding." << std::endl;
// Add access control or other logic here if needed
if (realSubject_) {
realSubject_->request();
} else {
std::cout << "Proxy: RealSubject is unavailable." << std::endl;
}
}
private:
std::shared_ptr<RealSubject> realSubject_;
};
// Client code
int main() {
auto realSubject = std::make_shared<RealSubject>();
auto proxy = std::make_shared<Proxy>(realSubject);
proxy->request();
// Simulate RealSubject becoming unavailable
realSubject.reset();
proxy->request();
return 0;
}
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for scenarios like remote access, security checks, or lazy initialization. The Subject interface defines the common interface for both the real object (RealSubject) and the proxy (Proxy). The Proxy controls access to the RealSubject, potentially adding functionality before or after the real object’s method is called. This C# implementation uses interfaces to define the contract, which is a common and preferred approach in C# for loose coupling and testability. The proxy handles the creation of the real subject only when needed.
// Define the common interface for the real object and the proxy
public interface ISubject
{
void Request();
}
// The real object
public class RealSubject : ISubject
{
public void Request()
{
Console.WriteLine("RealSubject: Handling request.");
}
}
// The proxy
public class Proxy : ISubject
{
private ISubject? _realSubject;
public void Request()
{
if (_realSubject == null)
{
Console.WriteLine("Proxy: Initializing RealSubject.");
_realSubject = new RealSubject();
}
Console.WriteLine("Proxy: Logging request before forwarding.");
_realSubject.Request();
Console.WriteLine("Proxy: Logging request after forwarding.");
}
}
// Client code
public class Client
{
public static void Main(string[] args)
{
Proxy proxy = new Proxy();
proxy.Request();
proxy.Request(); // Demonstrates lazy initialization
}
}
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for adding functionality like access control, logging, or lazy loading without modifying the original object. In this TypeScript example, we create a SecureRemoteData proxy for a RemoteData object. The proxy intercepts get requests and checks if the user has permission to access the data before forwarding the request. This implementation leverages TypeScript’s built-in Proxy object for clean and type-safe interception of operations. The use of interfaces promotes loose coupling and maintainability, aligning with TypeScript best practices.
// Define the interface for the real object
interface RemoteData {
data: string;
sensitiveData: string;
}
// The real object
const realData: RemoteData = {
data: "Public information",
sensitiveData: "Confidential information",
};
// Define the handler for the proxy
const handler: ProxyHandler<RemoteData> = {
get: (target, prop, receiver) => {
const userRole = "admin"; // Simulate user role
if (prop === "sensitiveData" && userRole !== "admin") {
return "Access denied";
}
return Reflect.get(target, prop, receiver);
},
};
// Create the proxy
const secureData = new Proxy(realData, handler);
// Usage
console.log(secureData.data); // Output: Public information
console.log(secureData.sensitiveData); // Output: Confidential information (if user is admin) or Access denied
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for adding functionality like access control, logging, or validation before operations are performed on the original object. In JavaScript, the Proxy object natively supports this pattern, allowing interception of fundamental operations.
The code creates a Subject class representing the real object and a Proxy class that wraps it. The Proxy intercepts calls to the Subject’s methods and adds logging before executing them. This demonstrates a simple use case – logging – but the Proxy can be extended to handle more complex scenarios like validation or access control. Using the built-in Proxy object is the most idiomatic way to implement this pattern in modern JavaScript, avoiding the need for manual interception or inheritance.
// Subject (Real Object)
class Subject {
doSomething() {
console.log("Subject: Doing something.");
}
doAnotherThing() {
console.log("Subject: Doing another thing.");
}
}
// Proxy
class Proxy {
constructor(subject) {
this.subject = subject;
}
get(target, prop, receiver) {
console.log(`Proxy: Accessing property "${prop}".`);
return Reflect.get(target, prop, receiver);
}
apply(target, thisArg, argumentsList) {
console.log("Proxy: Calling method.");
return target.apply(thisArg, argumentsList);
}
}
// Usage
const subject = new Subject();
const proxy = new Proxy(subject, {
get: new Proxy().get,
apply: new Proxy().apply
});
proxy.doSomething();
proxy.doAnotherThing();
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. The proxy object has the same interface as the real object, but it intercepts method calls and performs additional actions before or after forwarding them to the real object. This implementation uses Python’s dynamic nature to achieve this. The Subject interface is implicitly defined by the methods called on the proxy. The RealSubject is the actual object, and Proxy controls access to it, in this case, by printing a message before and after the real subject’s method is called. This approach is Pythonic as it leverages duck typing and avoids explicit interface declarations.
class RealSubject:
def request(self):
print("RealSubject: Handling request.")
class Proxy:
def __init__(self, real_subject):
self.real_subject = real_subject
def request(self):
print("Proxy: Logging before request.")
self.real_subject.request()
print("Proxy: Logging after request.")
def client_code(subject):
subject.request()
if __name__ == "__main__":
real_subject = RealSubject()
proxy = Proxy(real_subject)
print("Client: I'm not aware of the RealSubject.")
client_code(proxy)
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This is useful for adding functionality like access control, logging, or caching before forwarding requests to the real subject. In this Java example, we have a Subject interface representing a resource, a RealSubject implementing the resource, and a ProxySubject that intercepts calls to the RealSubject. The proxy checks if the real subject exists and creates it if necessary, then logs the request before delegating to the real subject. This implementation utilizes interfaces to define the contract, a common practice in Java for loose coupling and testability.
// Subject interface
interface Subject {
String operation(String data);
}
// Real Subject
class RealSubject implements Subject {
@Override
public String operation(String data) {
System.out.println("RealSubject: Handling request.");
return "RealSubject: Result for " + data;
}
}
// Proxy Subject
class ProxySubject implements Subject {
private RealSubject realSubject;
private boolean isCreated = false;
@Override
public String operation(String data) {
if (!isCreated) {
System.out.println("ProxySubject: Creating RealSubject.");
realSubject = new RealSubject();
isCreated = true;
}
System.out.println("ProxySubject: Logging request: " + data);
String result = realSubject.operation(data);
System.out.println("ProxySubject: Logging response: " + result);
return result;
}
}
// Client
public class ProxyExample {
public static void main(String[] args) {
Subject proxy = new ProxySubject();
proxy.operation("Hello");
proxy.operation("World");
}
}