El lenguaje de programación Rust ha ganado popularidad en los últimos años gracias a su enfoque en la seguridad, la concurrencia y el rendimiento. Aunque Rust es conocido por su sistema de propiedad que evita errores comunes en memoria, también es un lenguaje flexible y poderoso que permite implementar patrones de diseño clásicos, como el patrón Proxy.
El patrón Proxy es un patrón de diseño estructural que proporciona un sustituto o marcador de posición para otro objeto. Un proxy controla el acceso al objeto real, permitiendo realizar operaciones antes o después de que se acceda al objeto, o incluso modificar el comportamiento del objeto real.
1. Sujeto real (Real Subject): El objeto original que el proxy controla.
2. Proxy: Un objeto intermediario que controla el acceso al sujeto real.
3. Cliente: La entidad que interactúa con el proxy en lugar de interactuar directamente con el sujeto real.
Al utilizar el patrón Proxy, puedes obtener los siguientes beneficios:
A continuación, veremos cómo implementar el patrón Proxy en Rust. Para ello, seguiremos un enfoque paso a paso.
Para empezar, asegúrate de tener Rust instalado en tu máquina. Si no lo tienes, puedes instalarlo usando el siguiente comando:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Crea un nuevo proyecto de Rust:
cargo new proxy_pattern
cd proxy_pattern
En Rust, podemos definir un sujeto común usando un trait
. Un trait
es similar a una interfaz en otros lenguajes de programación.
trait Subject {
fn request(&self);
}
Ahora implementaremos una estructura que represente al sujeto real y que implemente el trait
Subject
.
struct RealSubject;
impl Subject for RealSubject {
fn request(&self) {
println!("RealSubject: Handling request.");
}
}
El proxy implementará el mismo trait
Subject
, y delegará las llamadas al sujeto real. Además, añadirá funcionalidades adicionales, como control de acceso y registro de operaciones.
struct ProxySubject {
real_subject: RealSubject,
}
impl ProxySubject {
fn new(real_subject: RealSubject) -> Self {
ProxySubject { real_subject }
}
fn check_access(&self) -> bool {
println!("ProxySubject: Checking access prior to firing a request.");
// Aquí podrías agregar lógica para verificar permisos, por ejemplo.
true
}
fn log_access(&self) {
println!("ProxySubject: Logging the time of request.");
// Aquí podrías registrar la operación en un sistema de logging.
}
}
impl Subject for ProxySubject {
fn request(&self) {
if self.check_access() {
self.real_subject.request();
self.log_access();
}
}
}
El cliente interactuará con el proxy como si estuviera interactuando con el sujeto real. Esto permite que el cliente no sepa si está tratando con un proxy o con el objeto real.
fn client_code(subject: &dyn Subject) {
subject.request();
}
fn main() {
println!("Client: Executing the client code with a real subject:");
let real_subject = RealSubject;
client_code(&real_subject);
println!("\nClient: Executing the same client code with a proxy:");
let proxy = ProxySubject::new(real_subject);
client_code(&proxy);
}
Para compilar y ejecutar el código, usa el siguiente comando:
cargo run
Deberías obtener una salida similar a la siguiente:
Client: Executing the client code with a real subject:
RealSubject: Handling request.
Client: Executing the same client code with a proxy:
ProxySubject: Checking access prior to firing a request.
RealSubject: Handling request.
ProxySubject: Logging the time of request.
Subject
: Define la interfaz común que el sujeto real y el proxy deben implementar.
RealSubject
: La implementación concreta del sujeto real, que contiene la lógica principal.
ProxySubject
: El proxy controla el acceso al RealSubject
. En este caso, se verifica el acceso antes de delegar la solicitud y se registra la operación después de que se ha procesado la solicitud.
client_code
): Interactúa con el Subject
sin saber si está tratando con un proxy o con el sujeto real, lo que proporciona flexibilidad y ocultamiento de la complejidad interna.
El uso de Rust para implementar el patrón Proxy tiene varias ventajas:
El patrón Proxy es un patrón de diseño estructural útil que permite controlar el acceso a un objeto, agregar funcionalidades adicionales como almacenamiento en caché o registro de eventos, y mejorar la seguridad de la aplicación. Implementar este patrón en Rust es relativamente sencillo gracias a las características avanzadas del lenguaje, como los traits
y el sistema de propiedad.
Rust, con su enfoque en la seguridad y el rendimiento, es un lenguaje excelente para implementar patrones de diseño como el Proxy, especialmente en aplicaciones que requieren alto rendimiento y seguridad. Con la implementación de este patrón, puedes mejorar significativamente la estructura y funcionalidad de tus aplicaciones.
Si deseas seguir aprendiendo, puedes explorar otros patrones de diseño en Rust, como el patrón Decorator, Adapter, y Facade, que también ofrecen soluciones elegantes para problemas comunes en el desarrollo de software.
Jorge García
Fullstack developer