Patrón de diseño de proxy para la comunicación de objetos en Python

La memoria y el tiempo son los dos principales desafíos al trabajar con objetos grandes. Por lo tanto, es importante reutilizar estos objetos para generar nuevas referencias en lugar de crearlos en cada nueva solicitud. Y lo más importante, la memoria debe liberarse después de que todas las secciones del código hayan terminado de trabajar en ella.

Un patrón de diseño de proxy es la mejor manera posible de lograr la inicialización de objetos grandes. Separa el código del cliente del objeto mediante la creación de un objeto proxy sustituto que se comporta como un objeto real. Aquí, el código del cliente interactúa con la clase de proxy: tiene una instancia de objeto real. Además de la inicialización de objetos, también proporciona las mejores soluciones posibles para el registro, las conexiones de red, el acceso a objetos compartidos, el recuento de referencias y más.

Algunas ventajas de usar un patrón de diseño proxy son:

  1. Garantiza el acceso distribuido, controlado o inteligente mediante el uso de un nivel adicional de direccionamiento indirecto.
  2. Protege el objeto real de una complejidad innecesaria al agregar un envoltorio.
  3. Evita la creación de instancias de objetos inadecuados y puede optimizar el rendimiento de una aplicación

Sin embargo, a veces, el patrón de proxy aumenta el tiempo de respuesta del objeto: cuando se solicita el objeto por primera vez, la inicialización del objeto llevará más tiempo.

Implementación

Implementemos un código de Python para instanciar un objeto grande, que contiene 10 millones de dígitos: RealClass . Dado que contiene un objeto grande, es mejor interactuar con el objeto utilizando un proxy, ProxyClass  , en lugar de iniciar una comunicación directa.

Patrón de diseño de proxy

En primer lugar, vamos a crear una clase abstracta, AbstractClass, que proporcione una interfaz para RealClass y ProxyClass. La clase abstracta tiene un método llamado sort_digits, y la clase real hereda de la clase abstracta. La clase proxy utiliza la instancia de RealClass y facilita la comunicación con el cliente.

Python3

import abc
import random
  
  
class AbstractClass(metaclass=abc.ABCMeta):
    """ interface for real and proxy object """
    @abc.abstractmethod
    def sort_digits(self, reverse=False):
        pass
  
  
class RealClass(AbstractClass):
    """ RealClass that holds a larger object """
  
    def __init__(self):
        self.digits = []
  
        for i in range(1000000):
            self.digits.append(random.random())
  
    def sort_digits(self, reverse=False):
        self.digits.sort()
  
        if reverse:
            self.digits.reverse()
  
  
class ProxyClass(AbstractClass):
    """ A proxy class that has the same interface as RealClass. """
  
    ref_count = 0
  
    def __init__(self):
        """ Creates an object if it doesn't exist and caches it otherwise """
  
        if not getattr(self.__class__, 'cached_object', None):
            self.__class__.cached_object = RealClass()
            print('New object generated')
        else:
            print('Using cached object')
  
        self.__class__.ref_count += 1
        print('Reference Count:', self.__class__.ref_count)
  
    def sort_digits(self, reverse=False):
        print('Sort method')
        print(locals().items())
          
        # invokes the sort_digits method of real class
        self.__class__.cached_object.sort_digits(reverse=reverse)
  
    def __del__(self):
        """ Delete the object when the number of reference is 0 """
        self.__class__.ref_count -= 1
  
        if self.__class__.ref_count == 0:
            print('Deleting cached object')
            del self.__class__.cached_object
  
        print('Reference Count:', self.__class__.ref_count)
  
  
if __name__ == '__main__':
    proxA = ProxyClass()
    print()
  
    proxB = ProxyClass()
    print()
  
    proxC = ProxyClass()
    print()
  
    proxA.sort_digits(reverse=True)
    print()
  
    print('Deleting proxA')
    del proxA
  
    print('Deleting proxB')
    del proxB
  
    print('Deleting proxC')
    del proxC

Producción:

Nuevo objeto generado
Recuento de referencias: 1

Uso de objetos almacenados en caché
Recuento de referencias: 2

Uso de objetos almacenados en caché
Recuento de referencias: 3

Ordenar método
dict_items([(‘reverse’, True), (‘self’, <__main__.ProxyClass object at 0x7ff50f73e0b8>)])

Eliminando proxA
Recuento de referencias: 2
Eliminando proxB
Recuento de referencias: 1
Eliminando proxC
Eliminando objeto almacenado en caché
Recuento de referencias: 0

Veamos el diseño de ProxyClass. Crea una instancia de RealClass si no se ha creado antes. Si el objeto ya existe, la clase de proxy incrementa el recuento de referencias y devuelve un nuevo enlace a la clase real. Y el método de clasificación en la clase de proxy llama al método de clasificación de la clase real, utilizando la referencia almacenada en caché. Al final, el método destructor disminuye el recuento de referencias en cada llamada y, cuando no quedan referencias, elimina el objeto.  

El patrón de diseño de proxy optimiza el rendimiento de una aplicación al almacenar en caché los objetos de uso frecuente y también mejora la seguridad de una aplicación al verificar los derechos de acceso. Aparte de estos, facilita las interacciones del sistema remoto.

Publicación traducida automáticamente

Artículo escrito por SonuGeorge y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *