1. Definition
The Proxy Design Pattern provides a surrogate or placeholder for another object to control access to it. It is a structural pattern that involves a class representing the functionality of another class.
2. Problem Statement
Suppose you’re developing a document viewer application where documents can be quite large. Loading every document in memory every time the user clicks on it, even if just for previewing its title, can be inefficient and slow.
3. Solution
Instead of loading the entire document, we can use a proxy that loads only essential data initially (like title or thumbnail). The full document is loaded only when the user requests more operations (like editing or viewing the full document). The proxy acts as a stand-in for the real object and controls access to it.
4. Real-World Use Cases
1. Image or document viewers where heavy objects (large images or documents) need to be loaded.
2. Access control proxies that control access to the actual object based on permissions.
3. Virtual proxies that delay object creation until it’s actually needed.
4. Remote proxies representing objects in different address spaces.
5. Implementation Steps
1. Define an interface that both the RealObject and Proxy classes will implement.
2. Create the RealObject class that provides the actual functionalities.
3. Design the Proxy class which maintains a reference to a RealObject.
4. The Proxy class controls access to the RealObject and can either delay its creation or alter its function.
6. Implementation
// Step 1: Define an interface
public interface Document {
void displayTitle();
void displayContent();
}
// Step 2: RealObject providing actual functionalities
public class ActualDocument implements Document {
private String content;
public ActualDocument(String content) {
this.content = content;
loadDocument();
}
private void loadDocument() {
System.out.println("Loading the document...");
}
@Override
public void displayTitle() {
System.out.println("Document Title");
}
@Override
public void displayContent() {
System.out.println(content);
}
}
// Step 3: Proxy class controlling access to RealObject
public class DocumentProxy implements Document {
private ActualDocument actualDocument;
private String content;
public DocumentProxy(String content) {
this.content = content;
}
@Override
public void displayTitle() {
System.out.println("Document Title");
}
@Override
public void displayContent() {
if (actualDocument == null) {
actualDocument = new ActualDocument(content);
}
actualDocument.displayContent();
}
}
// Client code
public class Client {
public static void main(String[] args) {
Document document = new DocumentProxy("This is the actual content of the document.");
document.displayTitle(); // Doesn't load the actual content
document.displayContent(); // Loads and displays the actual content
}
}
Output:
Document Title Loading the document... This is the actual content of the document.
Explanation:
The client interacts with the DocumentProxy, which doesn't load the actual content until it's needed. Initially, only the title is shown. When the content is requested, the proxy loads the ActualDocument and displays its content.
7. When to use?
1. When you need to add some functionality to an object, but it’s not feasible to modify the actual class.
2. To delay the creation and initialization of heavy objects until they are required.
3. To control access to the actual object.
4. To represent objects in different address spaces or to create a local representation of a remote server instance.