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
ExpensiveObject
y controla su creación y acceso. - Uso del Proxy: Creamos una instancia de
Proxy
y llamamos al métodoprocess
. La primera vez que se llama aprocess
, elExpensiveObject
se 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