Deep Dive into Structural Patterns - The Proxy Pattern.
Hey software designers! Today, we’re diving into the Proxy pattern. This pattern provides a surrogate or placeholder for another object to control access to it. Let’s explore its workings, benefits, and real-world applications with detailed examples.
What is the Proxy Pattern?
The Proxy pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. It acts as an intermediary that can add functionality before or after delegating the request to the real object.
Real-World Scenario
Imagine you’re developing an image viewer application that loads high-resolution images. Loading these images can be time-consuming, and you want to display a placeholder image while the high-resolution image is being loaded in the background.
The Problem
When dealing with resource-intensive objects, directly accessing these objects can lead to performance issues and unnecessary resource consumption. Hardcoding the logic to manage these objects can result in a tightly coupled and inefficient codebase.
Without Proxy Pattern
class HighResolutionImage
def initialize(filename)
@filename = filename
load_image
end
def load_image
puts "Loading high-resolution image: #{@filename}"
# Simulate a time-consuming loading process
sleep(2)
puts "Image loaded: #{@filename}"
end
def display
puts "Displaying image: #{@filename}"
end
end
image = HighResolutionImage.new('large_image.jpg')
image.display
Drawbacks: The image is loaded immediately, leading to a delay before it can be displayed.
The Solution: Proxy Pattern
Using the Proxy pattern, we can control access to the high-resolution image and display a placeholder image while the real image is being loaded in the background.
With Proxy Pattern
Step 1: Define the Subject Interface
class Image
def display
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
end
Step 2: Create the Real Subject
class HighResolutionImage < Image
def initialize(filename)
@filename = filename
load_image
end
def load_image
puts "Loading high-resolution image: #{@filename}"
# Simulate a time-consuming loading process
sleep(2)
puts "Image loaded: #{@filename}"
end
def display
puts "Displaying image: #{@filename}"
end
end
Step 3: Create the Proxy
class ImageProxy < Image
def initialize(filename)
@filename = filename
@real_image = nil
end
def display
if @real_image.nil?
puts "Displaying placeholder image"
@real_image = HighResolutionImage.new(@filename)
end
@real_image.display
end
end
Step 4: Implement Client Code
image = ImageProxy.new('large_image.jpg')
image.display
Benefits: Controls access to the high-resolution image, displaying a placeholder image while the real image is being loaded.
Real-World Benefits
Scenario: Managing Access to Resource-Intensive Objects
Imagine you need to manage access to resource-intensive objects in a large-scale application. Using the Proxy pattern, you can control access to these objects and add functionality before or after delegating the request to the real object.
Without Proxy Pattern:
class DatabaseConnection
def connect
puts 'Establishing database connection...'
# Simulate a time-consuming connection process
sleep(2)
puts 'Database connection established.'
end
def execute_query(query)
puts "Executing query: #{query}"
end
end
connection = DatabaseConnection.new
connection.connect
connection.execute_query('SELECT * FROM users')
Drawbacks: The connection is established immediately, leading to a delay before the query can be executed.
With Proxy Pattern:
class DatabaseConnectionProxy
def initialize
@real_connection = nil
end
def connect
if @real_connection.nil?
puts 'Displaying placeholder message'
@real_connection = DatabaseConnection.new
@real_connection.connect
end
end
def execute_query(query)
connect
@real_connection.execute_query(query)
end
end
connection = DatabaseConnectionProxy.new
connection.execute_query('SELECT * FROM users')
Benefits: Controls access to the database connection, displaying a placeholder message while the connection is being established.
Conclusion
The Proxy pattern is a powerful tool for controlling access to objects and adding functionality before or after delegating the request to the real object. It promotes efficiency, scalability, and maintainability in your code. By using the Proxy pattern, you can manage access to resource-intensive objects and improve the performance of your application. Incorporate the Proxy pattern into your design strategies to build more robust and adaptable software systems.
Stay tuned for more insights into software design principles and patterns.
Thôi Lo Code Đi Kẻo Sếp nạt!