Desde la perspectiva del diseño orientado a objetos la habilidad para atrapar accesos a atributos provee algunas nuevas soluciones a viejos problemas. Un buen ejemplo es el patrón Proxy, el cual es utilizado cuando un objeto tiene que ser escudado de sus clientes. Puede haber varias razones para ello: conteo de referencias, distintos niveles de permisos de acceso,evaluación floja del estado de un objeto y otras. La estructura del objeto en tiempo de ejecución para el patrón es mostrada en la figura 10.
Figura 10. Estructura del objeto en tiempo de ejecución |
El cliente no necesita saber que no está accediendo al objeto real(Subject) directamente. En otras palabras, el proxy substituye al objeto real. En C++ esto podría significar que ambos, el proxy y la clase sujeto tienen una clase común de base. En Python el mismo efecto puede ser logrado enmascarando la instancia del proxy como el objeto proveyendo la misma interface de métodos. Nuestra clase proxy en la figura 11 está basada en la clase cuasiuniversal Wrapper [vR96]. Como tal, la clase Proxy es sólo una envolvente trivial para cualquier objeto. Sin embargo, su función principal es la de servir a su clase base para implementaciones más específicas. Dado que el método __gettattr__ es llamado sólo como el último recurso el proxy puede manejar un método sujeto diferentemente "sobrecargándolo" en la claseproxy. Consideremos la siguiente situación: accedemos una instancia de la clase RGB (Fig. 12) primero directamente, luego utilizando una instancia de Proxy genérica como una envolvente y finalmente a través de una instancia de NoBlueProxy (Fig. 13):
>>> rgb = RGB( 100, 192, 240 )
>>> rgb.Red()
100
>>> proxy = Proxy( rgb )
>>> proxy.Green()
192
>>> noblue = NoBlueProxy( rgb )
>>> noblue.Green()
192
>>> noblue.Blue()
0
class Proxy: def __init__( self, subject ): self.__subject = subject def __getattr__( self, name ): return getattr( self.__subject, name )
Figura 11. Clase base Proxy |
class RGB: def __init__( self, red, green, blue ): self.__red = red self.__green = green self.__blue = blue def Red( self ): return self.__red def Green( self ): return self.__green def Blue( self ): return self.__blue
Figura 12. La clase Subject |
class NoBlueProxy( Proxy ): def Blue( self ): return 0
Figura 13. Una implementación más específica de proxy |
Mientras que python provee algunos mecanismos que son usualmente implementados con el patrón Proxy (por ejemplo el conteo de referencias simples)el patrón es todavía altamente aplicable a la comunidad Python. Un excelente ejemplo es el paquete deDaniel Larsson RemoteCall [Lar97], que provee un mecanismo simple para aplicaciones distribuidas. Uno de los conceptos clave en el sistema es el rol de agente, el cual es una representación del lado del cliente de los objetos del lado del servidor - en otras palabras, proxies. La historia del paquete también demuestra un aspecto digno de mencionar de los patrones en general: el autor reconoció que había aplicado un patrón después después de su implementación.