En programación de computadoras , el patrón de proxy es un patrón de diseño de software . Un proxy , en su forma más general, es una clase que funciona como interfaz con otra cosa. El proxy podría interactuar con cualquier cosa: una conexión de red, un objeto grande en la memoria, un archivo o algún otro recurso que sea costoso o imposible de duplicar. En resumen, un proxy es un objeto contenedor o agente al que el cliente llama para acceder al objeto de servicio real detrás de escena. El uso del proxy puede ser simplemente reenvíoal objeto real, o puede proporcionar lógica adicional. En el proxy, se pueden proporcionar funciones adicionales, por ejemplo, el almacenamiento en caché cuando las operaciones en el objeto real consumen muchos recursos, o la verificación de las condiciones previas antes de que se invoquen las operaciones en el objeto real. Para el cliente, el uso de un objeto proxy es similar al uso del objeto real, porque ambos implementan la misma interfaz.
Descripción general
El patrón de diseño Proxy [1] es uno de los veintitrés patrones de diseño GoF bien conocidos que describen cómo resolver problemas de diseño recurrentes para diseñar software orientado a objetos flexible y reutilizable, es decir, objetos que son más fáciles de implementar, cambiar, probar y reutilizar.
¿Qué problemas puede resolver el patrón de diseño Proxy? [2]
- Se debe controlar el acceso a un objeto.
- Se debe proporcionar funcionalidad adicional al acceder a un objeto.
Al acceder a objetos sensibles, por ejemplo, debería ser posible comprobar que los clientes tengan los derechos de acceso necesarios.
¿Qué solución describe el patrón de diseño Proxy?
Defina un Proxy
objeto separado que
- se puede utilizar como sustituto de otro objeto (
Subject
) y - implementa funcionalidades adicionales para controlar el acceso a este tema.
Esto hace posible trabajar a través de un Proxy
objeto para realizar una funcionalidad adicional al acceder a un tema. Por ejemplo, para comprobar los derechos de acceso de los clientes que acceden a un objeto sensible.
Para actuar como sustituto de un sujeto, un proxy debe implementar la Subject
interfaz. Los clientes no pueden saber si trabajan con un sujeto o su proxy.
Consulte también el diagrama de secuencia y clase UML a continuación.
Estructura
Diagrama de secuencia y clase UML
En el diagrama de clases de UML anterior , la Proxy
clase implementa la Subject
interfaz para que pueda actuar como sustituto de los Subject
objetos. Mantiene una referencia ( realSubject
) al objeto sustituido ( RealSubject
) para que pueda reenviarle solicitudes ( realSubject.operation()
).
El diagrama de secuencia muestra las interacciones en tiempo de ejecución: el Client
objeto funciona a través de un Proxy
objeto que controla el acceso a un RealSubject
objeto. En este ejemplo, el Proxy
reenvía la solicitud al RealSubject
, que realiza la solicitud.
Diagrama de clase
Posibles escenarios de uso
Proxy remoto
En la comunicación de objetos distribuidos , un objeto local representa un objeto remoto (uno que pertenece a un espacio de direcciones diferente). El objeto local es un proxy para el objeto remoto y la invocación del método en el objeto local da como resultado la invocación del método remoto en el objeto remoto. Un ejemplo sería una implementación de cajero automático , donde el cajero automático podría contener objetos proxy para la información bancaria que existe en el servidor remoto.
Proxy virtual
En lugar de un objeto complejo o pesado, una representación de esqueleto puede resultar ventajosa en algunos casos. Cuando una imagen subyacente tiene un tamaño enorme, se puede representar mediante un objeto proxy virtual, cargando el objeto real a pedido.
Proxy de protección
Se puede utilizar un proxy de protección para controlar el acceso a un recurso en función de los derechos de acceso.
Ejemplo
C#
interfaz ICar { void DriveCar () ; }// Coche de clase pública de objeto real : ICar { public void DriveCar () { Console . WriteLine ( "¡Se ha conducido el coche!" ); } } // Proxy Object public class ProxyCar : ICar { controlador de controlador privado ; privado ICar realCar ; public ProxyCar ( controlador de controlador ) { this . conductor = conductor ; esto . realCar = nuevo coche (); } public void DriveCar () { if ( controlador . Edad < 16 ) Consola . WriteLine ( "Lo siento, el conductor es demasiado joven para conducir" ); más esto . realCar . DriveCar (); } } Conductor de clase pública { public int Age { get ; establecer ; } Public Driver ( int age ) { this . Edad = edad ; } }// ¿Cómo usar la clase Proxy anterior? privada vacío btnProxy_Click ( objeto emisor , EventArgs e ) { ICAR coche = nueva ProxyCar ( nuevo controlador ( 15 )); coche . DriveCar (); coche = nuevo ProxyCar ( nuevo controlador ( 25 )); coche . DriveCar (); }
Producción
Lo siento, el conductor es demasiado joven para conducir.¡El coche ha sido conducido!
Notas:
- Un proxy puede ocultar información sobre el objeto real al cliente.
- Un proxy puede realizar optimización como carga bajo demanda.
- Un apoderado puede realizar tareas de mantenimiento adicionales como tareas de auditoría.
- El patrón de diseño proxy también se conoce como patrón de diseño sustituto.
C ++
#include #include class ICar { public : virtual ~ ICar () { std :: cout << "¡ICar destructor!" << std :: endl ; } DriveCar vacío virtual () = 0 ; }; class Car : public ICar { public : void DriveCar () override { std :: cout << "¡Se ha conducido el automóvil!" << std :: endl ; } };class ProxyCar : public ICar { public : ProxyCar ( int driver_age ) : driver_age_ ( driver_age ) {} vacío DriveCar () anulación { si ( driver_age_ > 16 ) { real_car_ -> DriveCar (); } else { std :: cout << "Lo siento, el conductor es demasiado joven para conducir". << std :: endl ; } } privado : std :: unique_ptr < ICar > real_car_ = std :: make_unique < Car > (); int driver_age_ ; };int main () { std :: unique_ptr < ICar > car = std :: make_unique < ProxyCar > ( 16 ); coche -> DriveCar (); coche = std :: make_unique < ProxyCar > ( 25 ); coche -> DriveCar (); }
Cristal
clase abstracta AbstractCar abstract def drive endclass Car < AbstractCar def drive pone "¡Se ha conducido el coche!" fin finclass Driver getter age : Int32 def initialize ( @age ) end endclass ProxyCar < AbstractCar controlador de captador privado : Controlador captador privado real_car : AbstractCar def initialize ( @controlador ) @real_car = Coche . nuevo final def drive if driver . age <= 16 pone "Lo sentimos, el conductor es demasiado joven para conducir". más @real_car . extremo del extremo del extremo del impulsor # Controlador de programa = Controlador . coche nuevo ( 16 ) = ProxyCar . coche nuevo ( conductor ) . manejar driver = Driver . coche nuevo ( 25 ) = ProxyCar . coche nuevo ( conductor ) . manejar
Producción
Lo siento, el conductor es demasiado joven para conducir.¡El coche ha sido conducido!
Delphi / Object Pascal
// Unidad de patrón de Proxy Design DesignPattern . Proxy ;interfaztipo // Car Interface ICar = procedimiento de interfaz DriveCar ; terminar ; // Clase TCar, implementando ICar TCar = Class ( TInterfacedObject , ICar ) función de clase New : ICar ; procedimiento DriveCar ; Fin ; // Driver Interface IDriver = función de interfaz Age : Integer ; terminar ; // TDriver Class, implementando IDriver TDriver = Class ( TInterfacedObject , IDriver ) private FAge : Integer ; constructor público Create ( Age : Integer ) ; Sobrecarga ; función de clase New ( Age : Integer ) : IDriver ; función Edad : Entero ; Fin ; // Objeto Proxy TProxyCar = Class ( TInterfacedObject , ICar ) private FDriver : IDriver ; FRealCar : ICar ; constructor público Create ( Driver : IDriver ) ; Sobrecarga ; función de clase Nuevo ( controlador : IDriver ) : ICar ; procedimiento DriveCar ; Fin ; implementación{Implementación de TCar} función de clase TCar . Nuevo : ICar ; comenzar Resultado : = Crear ; terminar ;procedimiento TCar . DriveCar ; begin WriteLn ( '¡Se ha conducido el coche!' ) ; terminar ;{Implementación de TDriver}constructor TDriver . Crear ( Edad : Entero ) ; iniciar la creación heredada ; FAge : = Edad ; terminar ; función de clase TDriver . Nuevo ( Edad : Entero ) : IDriver ; comenzar Resultado : = Crear ( Edad ) ; terminar ;función TDriver . Edad : Entero ; comenzar Resultado : = FAge ; terminar ;{Implementación de TProxyCar}constructor TProxyCar . Crear ( controlador : IDriver ) ; iniciar la creación heredada ; Yo . FDriver : = Conductor ; Yo . FRealCar : = TCar . Crear AS ICar ; terminar ; función de clase TProxyCar . Nuevo ( controlador : IDriver ) : ICar ; begin Resultado : = Create ( Driver ) ; terminar ;procedimiento TProxyCar . DriveCar ; comience si ( FDriver . Edad <= 16 ) luego WriteLn ( 'Lo siento, el conductor es demasiado joven para conducir.' ) else FRealCar . DriveCar () ; terminar ;final .
Uso
programa Project1 ; {$ APPTYPE Console} usa DesignPattern . Proxy en 'DesignPattern.Proxy.pas' ; comience TProxyCar . Nuevo ( TDriver . Nuevo ( 16 )) . DriveCar ; TProxyCar . Nuevo ( TDriver . Nuevo ( 25 )) . DriveCar ; final .
Producción
Lo siento, el conductor es demasiado joven para conducir.¡El coche ha sido conducido!
Java
El siguiente ejemplo de Java ilustra el patrón de "proxy virtual". La ProxyImage
clase se usa para acceder a un método remoto.
El ejemplo crea primero una interfaz contra la cual el patrón crea las clases. Esta interfaz contiene solo un método para mostrar la imagen, llamado displayImage()
, que debe ser codificado por todas las clases que lo implementan.
La clase de proxy ProxyImage
se ejecuta en otro sistema que no sea la propia clase de imagen real y puede representar la imagen real de RealImage
allí. Se accede a la información de la imagen desde el disco. Usando el patrón de proxy, el código del ProxyImage
evita la carga múltiple de la imagen, accediendo a ella desde el otro sistema de manera que ahorra memoria. La carga diferida demostrada en este ejemplo no es parte del patrón de proxy, sino que es simplemente una ventaja que es posible gracias al uso del proxy.
Imagen de interfaz { public void displayImage (); }// En el sistema A, la clase RealImage implementa Image { nombre de archivo de cadena final privado ; / ** * Constructor * @param nombre de archivo * / public RealImage ( String nombre de archivo ) { this . nombre de archivo = nombre de archivo ; loadImageFromDisk (); } / ** * Carga la imagen desde el disco * / private void loadImageFromDisk () { System . fuera . println ( "Cargando" + nombre de archivo ); } / ** * Muestra la imagen * / public void displayImage () { System . fuera . println ( "Visualización" + nombre de archivo ); } }// En la clase System B , ProxyImage implementa Image { nombre de archivo de cadena final privado ; imagen privada de RealImage ; / ** * Constructor * @param nombre de archivo * / public ProxyImage ( String nombre de archivo ) { this . nombre de archivo = nombre de archivo ; } / ** * Muestra la imagen * / public void displayImage () { if ( image == null ) { image = new RealImage ( nombre de archivo ); } imagen . displayImage (); } }class ProxyExample { / ** * Método de prueba * / public static void main ( String final [] argumentos ) { Image image1 = new ProxyImage ( "HiRes_10MB_Photo1" ); Image image2 = new ProxyImage ( "HiRes_10MB_Photo2" ); imagen1 . displayImage (); // carga necesaria imagen1 . displayImage (); // cargando image2 innecesario . displayImage (); // carga necesaria image2 . displayImage (); // cargando image1 innecesario . displayImage (); // carga innecesaria } }
Producción
Cargando HiRes_10MB_Photo1Mostrando HiRes_10MB_Photo1Mostrando HiRes_10MB_Photo1Cargando HiRes_10MB_Photo2Mostrando HiRes_10MB_Photo2Mostrando HiRes_10MB_Photo2Mostrando HiRes_10MB_Photo1
JavaScript
// Driver class class Driver { constructor ( edad ) { this . edad = edad } }// Clase de auto class Car { drive () { console . log ( '¡Se ha conducido el coche!' ) } }// Proxy car class class ProxyCar { constructor ( controlador ) { this . car = new Car () esto . driver = driver } drive () { if ( este . controlador . edad <= 16 ) { consola . log ( 'Lo siento, el conductor es demasiado joven para conducir.' ) } else { this . coche . conducir () } } }// Ejecuta el programa const driver = new Driver ( 16 ) const car = new ProxyCar ( driver ) car . conducir ()const driver2 = nuevo Driver ( 25 ) const car2 = nuevo ProxyCar ( driver2 ) car2 . conducir ()
Producción
Lo siento, el conductor es demasiado joven para conducir.¡El coche ha sido conducido!
PHP
php interfaz de imagen { pública función displayImage (); }// En el sistema A, la clase RealImage implementa Image { cadena privada $ nombre de archivo = null ; función pública __construct ( cadena $ nombre de archivo ) { $ esto -> nombre de archivo = $ nombre de archivo ; $ esto -> loadImageFromDisk (); } / ** * Carga la imagen desde el disco * / función privada loadImageFromDisk () { echo "Cargando { $ this -> nombre de archivo } " . \ PHP_EOL ; } / ** * Muestra la imagen * / función pública displayImage () { echo "Mostrando { $ this -> nombre de archivo } " . \ PHP_EOL ; } } // En la clase System B , ProxyImage implementa Image { ¿ privado ? Imagen $ imagen = nulo ; cadena privada $ nombre de archivo = nulo ; función pública __construct ( cadena $ nombre de archivo ) { $ esto -> nombre de archivo = $ nombre de archivo ; } / ** * Muestra la imagen * / función pública displayImage () { if ( $ this -> image === null ) { $ this -> image = new RealImage ( $ this -> nombre de archivo ); } $ esto -> imagen -> displayImage (); } } $ image1 = new ProxyImage ( "HiRes_10MB_Photo1" ); $ image2 = new ProxyImage ( "HiRes_10MB_Photo2" );$ imagen1 -> displayImage (); // Carga necesaria $ image1 -> displayImage (); // Cargando $ imagen2 innecesaria -> displayImage (); // Carga necesaria $ image2 -> displayImage (); // Cargando $ imagen1 innecesaria -> displayImage (); // Carga innecesaria
Producción
Cargando HiRes_10MB_Photo1 Mostrando HiRes_10MB_Photo1 Mostrando HiRes_10MB_Photo1 Cargando HiRes_10MB_Photo2 Mostrando HiRes_10MB_Photo2 Mostrando HiRes_10MB_Photo2 Mostrando HiRes_10MB_Photo1
Pitón
"" " Ejemplo de patrón de proxy. " "" De abc import ABCMeta , método abstractoNOT_IMPLEMENTED = "Debería implementar esto".clase AbstractCar : __metaclass__ = ABCMeta @abstractmethod def drive ( self ): generar NotImplementedError ( NOT_IMPLEMENTED )class Car ( AbstractCar ): def drive ( self ) -> None : print ( "¡Se ha conducido el automóvil!" )class Driver : def __init__ ( self , age : int ) -> None : self . edad = edadclase ProxyCar ( AbstractCar ): def __init__ ( self , driver ) -> None : self . car = Car () self . driver = conductor def drive ( self ) -> None : if self . conductor . edad <= 16 : print ( "Lo siento, el conductor es demasiado joven para conducir." ) else : self . coche . conducir ()driver = Driver ( 16 ) car = ProxyCar ( conductor ) car . conducir ()driver = Driver ( 25 ) car = ProxyCar ( conductor ) car . conducir ()
Producción
Lo siento, el conductor es demasiado joven para conducir.¡El coche ha sido conducido!
Oxido
rasgo ICar { fn drive ( & self );}struct Car {} impl ICAR para coches { fn drive ( & self ) { println! ( "¡Se ha conducido el coche!" ); }}impl Car { fn nuevo () -> Coche { Coche {} }}struct ProxyCar <' a > { coche_real : & ' a ICar , driver_age : i32 ,}impl <' a > ICar para ProxyCar <' a > { fn drive ( & self ) { si yo . driver_age > 16 { yo . coche_real . conducir (); } más { println! ( "Lo siento, el conductor es demasiado joven para conducir" ). } }}impl <' a > ProxyCar <' a > { fn nueva ( driver_age : i32 , other_car : Y ' un ICAR ) -> ProxyCar { ProxyCar { coche_real : otro_coche , driver_age : driver_age , } }}# [cfg (prueba)] pruebas de mod { use super :: * ; #[prueba] fn test_underage () { let car = Car :: new (); let proxy_car = ProxyCar :: new ( 16 , & car ); proxy_car . conducir (); } #[prueba] fn test_can_drive () { let car = Car :: new (); let proxy_car = ProxyCar :: new ( 17 , & car ); proxy_car . conducir (); }}
Producción
Lo siento, el coche es demasiado joven para que lo conduzcas.¡El coche ha sido conducido!
Ver también
Referencias
- ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Patrones de diseño: elementos de software orientado a objetos reutilizable . Addison Wesley. págs. 207 y siguientes . ISBN 0-201-63361-2.CS1 maint: varios nombres: lista de autores ( enlace )
- ^ "El patrón de diseño de Proxy - Problema, solución y aplicabilidad" . w3sDesign.com . Consultado el 12 de agosto de 2017 .
- ^ "El patrón de diseño Proxy - Estructura y colaboración" . w3sDesign.com . Consultado el 12 de agosto de 2017 .
enlaces externos
- Geary, David (22 de febrero de 2002). "Toma el control con el patrón de diseño Proxy" . JavaWorld . Consultado el 20 de julio de 2020 .
- Proyecto de código abierto PerfectJPattern , proporciona una implementación en componentes del patrón de proxy en Java
- Comparación de patrones de adaptador, proxy y fachada en Wayback Machine (archivado el 11 de marzo de 2012)
- Patrón de diseño de proxy
- Ejemplo de implementación de C ++ de patrón de proxy en Wayback Machine (archivado el 19 de octubre de 2014)
- Descripción del patrón de proxy del repositorio de patrones de Portland