Introducción
El patrón Proxy es un patrón estructural que proporciona un sustituto o marcador de posición para otro objeto. Un proxy controla el acceso a un objeto, permitiendo realizar ciertas acciones antes o después de que la solicitud llegue al objeto real. Este patrón es útil cuando se necesita agregar una capa de control sobre el acceso a un objeto.
Objetivos del Patrón Proxy:
- Controlar el acceso a un objeto.
- Reducir la carga de trabajo de un objeto costoso.
- Proveer una capa adicional de seguridad.
- Implementar un mecanismo de carga diferida (lazy initialization).
Tipos de Proxy
Existen varios tipos de proxies, cada uno con un propósito específico:
- Proxy Virtual: Retrasa la creación y carga de un objeto costoso hasta que sea necesario.
- Proxy Remoto: Representa un objeto que reside en un espacio de direcciones diferente (por ejemplo, en una máquina remota).
- Proxy de Protección: Controla el acceso a un objeto, permitiendo diferentes niveles de acceso.
- Proxy de Caché: Proporciona almacenamiento temporal de resultados costosos para mejorar el rendimiento.
Estructura del Patrón Proxy
La estructura del patrón Proxy incluye los siguientes componentes:
- Subject: Define la interfaz común para RealSubject y Proxy.
- RealSubject: El objeto real que el proxy representa.
- Proxy: Mantiene una referencia al RealSubject y controla el acceso a él.
Diagrama UML
+-----------+ +-----------+
| Client |------>| Proxy |
+-----------+ +-----------+
|
v
+-----------+
|RealSubject|
+-----------+Implementación en Código
A continuación, se presenta un ejemplo de implementación del patrón Proxy en Python.
Ejemplo: Proxy Virtual
Supongamos que tenemos una clase ExpensiveObject que es costosa de crear. Utilizaremos un proxy para retrasar su creación hasta que sea realmente necesario.
class ExpensiveObject:
def __init__(self):
self._load_data()
def _load_data(self):
print("Loading expensive data...")
def process(self):
print("Processing data...")
class Proxy:
def __init__(self):
self._real_subject = None
def process(self):
if self._real_subject is None:
self._real_subject = ExpensiveObject()
self._real_subject.process()
# Uso del Proxy
proxy = Proxy()
print("Proxy creado.")
proxy.process() # Aquí se crea el ExpensiveObject y se llama a su método process.
proxy.process() # Aquí no se crea de nuevo el ExpensiveObject, solo se llama a su método process.Explicación del Código
- ExpensiveObject: Esta es la clase costosa cuya creación queremos retrasar.
- Proxy: Esta clase contiene una referencia a
ExpensiveObjecty controla su creación y acceso. - Uso del Proxy: Creamos una instancia de
Proxyy llamamos al métodoprocess. La primera vez que se llama aprocess, elExpensiveObjectse crea y se carga. En llamadas subsecuentes, el objeto ya está creado y solo se llama a su métodoprocess.
Ejercicio Práctico
Ejercicio
Implementa un proxy de protección que controle el acceso a un objeto sensible basado en roles de usuario. El objeto sensible es una clase SensitiveData que tiene un método access_data.
class SensitiveData:
def access_data(self):
print("Accessing sensitive data...")
class ProtectionProxy:
def __init__(self, user_role):
self._user_role = user_role
self._real_subject = SensitiveData()
def access_data(self):
if self._user_role == "admin":
self._real_subject.access_data()
else:
print("Access denied. Insufficient permissions.")
# Uso del ProtectionProxy
proxy_admin = ProtectionProxy("admin")
proxy_admin.access_data() # Debe permitir el acceso.
proxy_user = ProtectionProxy("user")
proxy_user.access_data() # Debe denegar el acceso.Solución
class SensitiveData:
def access_data(self):
print("Accessing sensitive data...")
class ProtectionProxy:
def __init__(self, user_role):
self._user_role = user_role
self._real_subject = SensitiveData()
def access_data(self):
if self._user_role == "admin":
self._real_subject.access_data()
else:
print("Access denied. Insufficient permissions.")
# Uso del ProtectionProxy
proxy_admin = ProtectionProxy("admin")
proxy_admin.access_data() # Debe permitir el acceso.
proxy_user = ProtectionProxy("user")
proxy_user.access_data() # Debe denegar el acceso.Conclusión
El patrón Proxy es una herramienta poderosa para controlar el acceso a objetos y mejorar el rendimiento y la seguridad de una aplicación. Al entender y aplicar este patrón, los desarrolladores pueden crear sistemas más eficientes y seguros.
Resumen
- El patrón Proxy proporciona un sustituto para otro objeto para controlar el acceso a él.
- Hay varios tipos de proxies, incluyendo virtual, remoto, de protección y de caché.
- La implementación de un proxy puede mejorar el rendimiento y la seguridad de una aplicación.
- Los proxies son útiles en situaciones donde la creación de objetos es costosa o donde se requiere control de acceso.
En el siguiente módulo, exploraremos el patrón Chain of Responsibility, que permite pasar una solicitud a lo largo de una cadena de manejadores.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
- Historia y Origen de los Patrones de Diseño
- Clasificación de los Patrones de Diseño
- Ventajas y Desventajas de Usar Patrones de Diseño
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
- Ejemplos Prácticos de Uso de Patrones
- Patrones de Diseño en Proyectos Reales
- Refactorización Usando Patrones de Diseño
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
- Patrones de Diseño en Microservicios
- Patrones de Diseño en Sistemas Distribuidos
- Patrones de Diseño en Desarrollo Ágil
