Proxy Design Pattern for Object Communication in Python


Classes and objects are the fundamental elements of programming. These entities construct the entire logic and controls the access to different parts of the code. There could be a situation where we are restricted by the complexity of the operation and therefore, we require an efficient and optimized solution.

The Proxy Design Pattern is one such powerful technique of creating a proxy class instead of an instance of the real class. In this article, we will be exploring the basics of this technique and understand how we can use it to solve problems involving huge amount of data. Let’s begin with the discussion.

Understanding Proxy Design Pattern

In Proxy Design Pattern, we create a proxy class that acts as an interface for the real class. Now, the question is why we need to create an interface? Well, when we are dealing with problems that involves the use of large amount of memory and time, it is logical to reuse objects and data of the class instead of creating new references repeatedly.

  • After the creation of a class, we use of objects/instances to access the class data but if the class operations are complex then object instantiation should be regulated properly.

  • This is where Proxy design pattern comes into the picture. Initializing new objects for the real class that contains heavy data is an expensive approach. Instead, we can create a proxy class that behaves like a real class and can also be customized depending upon the need of the operation.

Consider a situation, where we have to computationally retrieve information for millions of government employees. If the client tries to directly access the real class by creating an instance for each call, then it would make the entire process very expensive. It is wiser to use a medium or an interface that has all the attributes of the real class and can be controlled through a proxy class.

Object Communication With the Proxy Design Pattern

Object communication refers to the transfer of the data between different proxy objects within the same pattern. We will only create one real class instance and rest of the operations will dependent on the different proxy objects and their interactions with each other.

We will create an abstract class that will serve as a template for creating real and proxy classes. This abstract class will be implemented by these concrete classes. Our task is to retrieve information related to the salaries of 2 million government employees. We will create two abstract methods for calculating the Salary and displaying the employee details.

Both of these two methods will be defined in the concrete/real class.

  • In the concrete class, the Salary of 2 million employees will be calculated and processed. The computational demand of this operation is very expensive and therefore we will create a proxy class.

  • In the proxy class, we will again implement the methods of the abstract class and also add an extra layer of customization. We customize our program to check whether the class attribute “real_OBJ” exists or not.

On executing the program for the 1st time, a real class object will be created and after this on every execution a cached object will be used. A cached object provides a faster platform for data reusability. In this manner we will use a single real object and control it with the help of different proxy objects.

Example

Following is an example of implementing Proxy Design Pattern for object communication.

import abc
class Abstract_Base_class(metaclass=abc.ABCMeta):
   @abc.abstractmethod
   def Sal_calculator(self, rate):
      pass
   @abc.abstractmethod
   def employee_details(self):
      pass
class concrete(Abstract_Base_class):
   def __init__(self):
      self.total_employees = []
      for x in range(2000000):
         self.total_employees.append(x)
   def employee_details(self):
      self.employeeSector = "Government"
      return len(self.total_employees), self.employeeSector
   def Sal_calculator(self, rate):
      self.total_sal = 150000 * rate * len(self.total_employees)
      return self.total_sal
class proxy(Abstract_Base_class):
   def __init__(self):
      if not getattr(self.__class__, "real_OBJ", None):
         self.__class__.real_OBJ = concrete()
         print("A real object is created")
      else:
         print("Object already exists, using cached object")
   def Sal_calculator(self, rate):
      return self.__class__.real_OBJ.Sal_calculator(rate)
   def employee_details(self):
      return self.__class__.real_OBJ.employee_details()
if __name__ == "__main__":
   first_Prox = proxy()
   print(f"The total Salary budget with a 12% rate is: {first_Prox.Sal_calculator(12)}")
   print(f"The total Salary budget with a 10% rate is: {first_Prox.Sal_calculator(10)}")
   print(f"The total Salary budget with a 15% rate is: {first_Prox.Sal_calculator(15)}")
   Second_Prox = proxy()
   print(f"The total number of employees and their sectors are: {Second_Prox.employee_details()}")
   Third_Prox = proxy()
   print("This is a 3rd proxy object")

Output

A real object is created
The total Salary budget with a 12% rate is: 3600000000000
The total Salary budget with a 10% rate is: 3000000000000
The total Salary budget with a 15% rate is: 4500000000000
Object already exists, using cached object
The total number of employees and their sectors are: (2000000, 'Government')
Object already exists, using cached object
This is a 3rd proxy object

Conclusion

During the course of this article, we covered the basics of proxy design pattern for object communication. We understood the significance of memory and time in computational operations. We used proxy objects to produce an optimized program. The expensive object calls can be dogged with the help of these objects. At last, we discussed a real-life problem of computing data for 2 million employees and used proxy objects to handle this complex operation.

Updated on: 19-Jan-2024

29 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements