Proxy Pattern¶
Category: Structural Pattern
Overview¶
Provide a surrogate or placeholder for another object to control access to it. This pattern is used to create a representative object that controls access to another object, which may be remote, expensive to create, or require protection.
Usage Guidelines¶
Use when:
- Defer expensive object creation until needed (lazy initialization)
- Control access based on permissions or authentication
- Access objects in different address spaces (remote objects)
- Log access to objects or cache results of expensive operations
Avoid when:
- Direct access is sufficient and simple
- No access control or lazy loading required
- Proxy overhead is unacceptable for performance
- Can modify original class directly
Implementation¶
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Optional
class Image(ABC):
"""Abstract interface for images."""
@abstractmethod
def display(self) -> str:
"""Display the image."""
pass
@abstractmethod
def get_filename(self) -> str:
"""Get the image filename."""
pass
class RealImage(Image):
"""Real image that is expensive to load."""
def __init__(self, filename: str) -> None:
"""Initialize and load the image."""
self.filename = filename
self._load_from_disk()
def _load_from_disk(self) -> None:
"""Simulate expensive loading operation."""
pass
def display(self) -> str:
"""Display the image."""
return f"Displaying {self.filename}"
def get_filename(self) -> str:
"""Get filename."""
return self.filename
class ImageProxy(Image):
"""Virtual proxy for lazy loading images."""
def __init__(self, filename: str) -> None:
"""Initialize proxy without loading image."""
self.filename = filename
self._real_image: Optional[RealImage] = None
def display(self) -> str:
"""Display image, loading it if necessary."""
if self._real_image is None:
self._real_image = RealImage(self.filename)
return self._real_image.display()
def get_filename(self) -> str:
"""Get filename without loading image."""
return self.filename
def is_loaded(self) -> bool:
"""Check if real image is loaded."""
return self._real_image is not None
Usage¶
# Virtual Proxy - lazy loading
image = ImageProxy("large_photo.jpg")
print(image.is_loaded()) # False - not loaded yet
print(image.display()) # Now loaded and displayed
print(image.is_loaded()) # True - already loaded
Trade-offs¶
Benefits:
- Controls access to real object
- Defers expensive operations until needed (lazy initialization)
- Implements authentication and authorization for access control
- Adds behavior without modifying real object
Drawbacks:
- Adds additional classes and indirection increasing complexity
- Proxy adds overhead affecting performance
- Lazy initialization may cause delays in response time
- Thread-safe proxies can be complex
Real-World Examples¶
- ORM frameworks with database proxy objects for lazy loading
- Virtual images as placeholders in documents
- Network proxies like HTTP proxies, SOCKS proxies
- Security proxies for authentication and authorization layers
Related Patterns¶
- Adapter
- Decorator
- Facade
API Reference¶
design_patterns.structural.proxy
¶
Proxy Pattern Module
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. There are several types of proxies: - Virtual Proxy: Controls access to expensive-to-create objects - Protection Proxy: Controls access based on permissions - Remote Proxy: Represents an object in a different address space - Caching Proxy: Caches results of expensive operations
Example
Using a virtual proxy for lazy loading:
Database
¶
Bases: ABC
Abstract interface for database.
Source code in src/design_patterns/structural/proxy.py
query(sql)
abstractmethod
¶
Execute a query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sql
|
str
|
SQL query. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Query result. |
DatabaseProxy
¶
Bases: Database
Caching proxy for database queries.
Source code in src/design_patterns/structural/proxy.py
Document
¶
Bases: ABC
Abstract interface for documents.
Source code in src/design_patterns/structural/proxy.py
Image
¶
Bases: ABC
Abstract interface for images.
Source code in src/design_patterns/structural/proxy.py
display()
abstractmethod
¶
ImageProxy
¶
Bases: Image
Virtual proxy for lazy loading images.
Source code in src/design_patterns/structural/proxy.py
__init__(filename)
¶
Initialize proxy without loading image.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Image filename. |
required |
display()
¶
Display image, loading it if necessary.
Returns:
| Type | Description |
|---|---|
str
|
Display message. |
get_filename()
¶
is_loaded()
¶
Check if real image is loaded.
Returns:
| Type | Description |
|---|---|
bool
|
True if loaded, False otherwise. |
Internet
¶
Bases: ABC
Abstract interface for internet access.
Source code in src/design_patterns/structural/proxy.py
connect(url)
abstractmethod
¶
Connect to a URL.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
URL to connect to. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Connection result. |
ProtectedDocumentProxy
¶
Bases: Document
Protection proxy that requires authentication.
Source code in src/design_patterns/structural/proxy.py
__init__(filename, user_role)
¶
Initialize protected document proxy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Document filename. |
required |
user_role
|
str
|
User's role (admin or user). |
required |
Source code in src/design_patterns/structural/proxy.py
read()
¶
write(content)
¶
Write to document (requires admin role).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
Content to write. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Write result or access denied message. |
Source code in src/design_patterns/structural/proxy.py
ProxyInternet
¶
Bases: Internet
Protection proxy that filters internet access.
Source code in src/design_patterns/structural/proxy.py
__init__()
¶
Initialize proxy with real internet and banned sites.
add_banned_site(site)
¶
Add a site to the banned list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
site
|
str
|
Site to ban. |
required |
connect(url)
¶
Connect to URL if not banned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url
|
str
|
URL to connect to. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Connection result or blocked message. |
Source code in src/design_patterns/structural/proxy.py
RealDatabase
¶
RealDocument
¶
Bases: Document
Real document implementation.
Source code in src/design_patterns/structural/proxy.py
__init__(filename)
¶
Initialize document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Document filename. |
required |
read()
¶
write(content)
¶
Write content to document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
Content to write. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Write confirmation. |
RealImage
¶
Bases: Image
Real image that is expensive to load.