Overview
The Proxy Pattern is a structural design pattern that provides a layer of control over object access. It acts as an intermediary between a client and a real object, adding an extra layer of functionality or security.
Key components of the Proxy Pattern:
Subject: The interface that defines the operations of the real object.
RealSubject: The actual object that implements the Subject interface and provides the desired functionality.
Proxy: The class that acts as a surrogate for the RealSubject. It controls access to the RealSubject and may perform additional logic before or after delegating calls to it.
Subject:
This interface defines the methods that both the Proxy and the RealSubject can implement. It represents the functionality that the client expects to access.
RealSubject:
This is the actual object that provides the desired functionality. It implements the Subject interface and defines the concrete behavior.
Proxy:
The Proxy class sits between the client and the RealSubject. It implements the Subject interface and might perform additional tasks before or after delegating the call to the RealSubject. These tasks could include:
Access control: Restricting access to the RealSubject based on permissions.
Lazy loading: Delaying the creation of the RealSubject until it's actually needed.
Caching: Storing results from the RealSubject to improve performance.
Logging: Recording calls made to the RealSubject for debugging purposes.
Example:
Consider a file download system where you want to add security checks before allowing users to download specific files.
// Subject Interface
interface Downloadable {
download(): void;
}
// RealSubject (Concrete File)
class File implements Downloadable {
private fileName: string;
constructor(fileName: string) {
this.fileName = fileName;
}
public download(): void {
console.log(`Downloading file: ${this.fileName}`);
}
}
// Proxy (with access control)
class SecureDownloadProxy implements Downloadable {
private readonly file: File;
private readonly user: string;
constructor(file: File, user: string) {
this.file = file;
this.user = user;
}
public download(): void {
if (this.hasPermission(this.user)) {
this.file.download();
} else {
console.log("Access Denied! You don't have permission to download this file.");
}
}
private hasPermission(user: string): boolean {
// Implement logic to check user permissions for the specific file
return user === "admin"; // Just an example
}
}
// Usage
const file = new File("important_data.txt");
const proxy = new SecureDownloadProxy(file, "user1");
proxy.download(); // Access Denied!
const adminProxy = new SecureDownloadProxy(file, "admin");
adminProxy.download(); // Downloading file: important_data.txt
Explanation:
The
Downloadableinterface defines thedownload()method.The
Fileclass is the RealSubject that performs the actual download.The
SecureDownloadProxyimplements theDownloadableinterface and checks user permissions before calling thedownload()method on theFileobject.
Pros and Cons of Proxy Pattern:
Pros:
Adds an extra layer of control over object access.
Improves code flexibility by separating concerns.
Enables additional functionality like security, caching, or lazy loading.
Cons:
Introduces an extra layer of complexity compared to direct object access.
Might cause additional overhead due to the proxy's involvement.
Applicability:
Use the Proxy Pattern when you need to control access to an object.
It allows for adding security checks, performance optimizations, or other functionalities before delegating calls to the real object.
The Proxy Pattern is useful for implementing lazy loading, caching, or logging mechanisms.