본문 바로가기
Learning Python Design Patterns

The Proxy Pattern

by 자동매매 2023. 3. 29.

The Proxy Pattern – Controlling Object Access

In the previous chapter, we started with a brief introduction to Structural patterns and went ahead to discuss about the Façade design pattern. We understood the concept of Façade with a UML diagram and also learned how it's applied in the real world with the help of Python implementations. You learned about the upsides and downsides of the Façade pattern in the FAQs section.

In this chapter, we take a step forward and deal with the Proxy pattern that falls under the hood of the Structural design patterns. We will get introduced to the Proxy pattern as a concept and go ahead with a discussion on the design pattern and see how it is used in software application development. We will work with a sample use case and implement it in Python v3.5.

In this chapter, we will cover the following topics in brief:

  • An introduction to proxy and Proxy design patterns
  • A UML diagram for the Proxy pattern
  • Variations of Proxy patterns
  • A real-world use case with the Python v3.5 code implementation
  • Advantages of the Proxy pattern
  • Comparison - Façade and the Proxy pattern
  • Frequently asked questions

[ 49 ]
The Proxy Pattern – Controlling Object Access

Understanding the Proxy design pattern

Proxy, in general terms, is a system that intermediates between the seeker and provider. Seeker is the one that makes the request, and provider delivers the resources in response to the request. In the web world, we can relate this to a proxy server. The clients (users in the World Wide Web), when they make a request to the website, first connect to a proxy server asking for resources such as a web page. The proxy server internally evaluates this request, sends it to an appropriate server, and gets back the response, which is then delivered to the client. Thus, a proxy server encapsulates requests, enables privacy, and works well in distributed architectures.

In the context of design patterns, Proxy is a class that acts as an interface to real objects. Objects can be of several types such as network connections, large objects in memory and file, among others. In short, Proxy is a wrapper or agent object that wraps the real serving object. Proxy could provide additional functionality to the object that it wraps and doesn't change the object's code. The main intention of the Proxy pattern is to provide a surrogate or placeholder for another object in order to control access to a real object.

The Proxy pattern is used in multiple scenarios such as the following:

  • It represents a complex system in a simpler way. For example, a system that involves multiple complex calculations or procedures should have a simpler interface that can act as a proxy for the benefit of the client.
  • It adds security to the existing real objects. In many cases, the client is not allowed to access the real object directly. This is because the real object can get compromised with malicious activities. This way proxies act as a shield against malicious intentions and protect the real object.
  • It provides a local interface for remote objects on different servers. A clear example of this is with the distributed systems where the client wants to run certain commands on the remote system, but the client may not have direct permissions to make this happen. So it contacts a local object (proxy) with the request, which is then executed by the proxy on the remote machine.
  • It provides a light handle for a higher memory-consuming object. Sometimes, you may not want to load the main objects unless they're really necessary. This is because real objects are really heavy and may need high resource utilization. A classic example is that of profile pictures of users on a website. You're much better off showing smaller profile images in the list view, but of course, you'll need to load the actual image to show the detailed view of the user profile.

[ 50 ]
Chapter 5*

Let's understand the pattern with a simple example. Consider the example of an Actor and his Agent. When production houses want to approach an Actor for a

movie, typically, they talk to the Agent and not to the Actor directly. Based on the schedule of the Actor and other engagements, the Agent gets back to the production house on the availability and interest in working in the movie. Now, in this scenario, instead of production houses directly talking to the Actor, the Agent acts as a Proxy

that handles all the scheduling & payments for the Actor.

The following Python code implements this scenario where the Actor is the Proxy. The Agent object is used to find out if the Actor is busy. If the Actor is busy, the Actor().occupied() method is called and if the Actor is not busy, the Actor().

available() method gets returned.

class Actor(object):

def __init__(self):

self.isBusy = False

def occupied(self):

self.isBusy = True

print(type(self).__name__ , "is occupied with current movie")

def available(self):

self.isBusy = False

print(type(self).__name__ , "is free for the movie")

def getStatus(self):

return self.isBusy

class Agent(object):

def __init__(self):

self.principal = None

def work(self):

self.actor = Actor()

if self.actor.getStatus(): self.actor.occupied() else: self.actor.available()

if __name__ == '__main__': r = Agent() r.work()

[ 51 ]
The Proxy Pattern – Controlling Object Access

The Proxy design pattern essentially does the following:

  • It provides a surrogate for another object so that you can control access to the original object
  • It is used as a layer or interface to support distributed access
  • It adds delegation and protects the real component from undesired impact

A UML class diagram for the Proxy pattern

We will now discuss the Proxy pattern with the help of the following UML diagram. As we discussed in the previous paragraph, the Proxy pattern has three main actors: the production house, Agent, and the Actor. Let's put these in a UML diagram and

see how the classes look:

As we observe the UML diagram, you'll realize that there are three main participants in this pattern:

  • Proxy: This maintains a reference that lets the Proxy access the real object. It provides an interface identical to the Subject so that Proxy can substitute the real subject. Proxies are also responsible for creating and deleting the RealSubject.
  • Subject: It provides a representation for both, the RealSubject and Proxy. As Proxy and RealSubject implement Subject, Proxy can be used wherever RealSubject is expected.
  • RealSubject: It defines the real object that the Proxy represents.

[ 52 ]
Chapter 5*

From the data structure's perspective, the UML diagram can be represented as follows:

  • Proxy: It is a class that controls access to the RealSubject class. It handles the client's requests and is responsible for creating or deleting RealSubject.
  • Subject/RealSubject: Subject is an interface that defines what RealSubject and Proxy should look like. RealSubject is an actual implementation of the Subject interface. It provides the real functionality that is then used by the client.
  • Client: It accesses the Proxy class for the work to be accomplished. The Proxy class internally controls access to RealSubject and directs the work requested by Client.

Understanding different types of Proxies

There are multiple common situations where Proxies are used. We talked about some of them in the beginning of this chapter. Based on how the Proxies are used, we can categorize them as virtual proxy, remote proxy, protective proxy, and smart proxy. Let's learn a little more about them in this section.

A virtual proxy

Here, you'll learn in detail about the virtual proxy. It is a placeholder for objects that are very heavy to instantiate. For example, you want to load a large image on your website. Now this request will take a long time to load. Typically, developers will create a placeholder icon on the web page suggesting that there's an image. However, the image will only be loaded when the user actually clicks on the icon thus saving the cost of loading a heavy image in memory. Thus, in virtual proxies, the real object is created when the client first requests or accesses the object.

A remote proxy

A remote proxy can be defined in the following terms. It provides a local representation of a real object that resides on a remote server or different address space. For example, you want to build a monitoring system for your application that has multiple web servers, DB servers, celery task servers, caching servers, among others. If we want to monitor the CPU and disk utilization of these servers, we need to have an object that is available in the context of where the monitoring application runs but can perform remote commands to get the actual parameter values. In such cases, having a remote proxy object that is a local representation of the remote object would help.

[ 53 ]
The Proxy Pattern – Controlling Object Access

A protective proxy

You'll understand more about the protective proxy with the following points. This proxy controls access to the sensitive matter object of RealSubject. For example, in today's world of distributed systems, web applications have multiple services that work together to provide functionality. Now, in such systems, an authentication service acts as a protective proxy server that is responsible for authentication and authorization. In this case, Proxy internally helps in protecting the core functionality of the website for unrecognized or unauthorized agents. Thus, the surrogate object checks that the caller has access permissions required to forward the request.

A smart proxy

Smart proxies interpose additional actions when an object is accessed. For example, consider that there's a core component in the system that stores states in a centralized location. Typically, such a component gets called by multiple different services

to complete their tasks and can result in issues with shared resources. Instead of services directly invoking the core component, a smart proxy is built-in and checks whether the real object is locked before it is accessed in order to ensure that no other object can change it.

The Proxy pattern in the real world

We will take up a payment use case to demonstrate a real-world scenario for the Proxy pattern. Let's say that you go to shop at a mall and like a nice denim shirt there. You would like to purchase the shirt but you don't have enough cash to do so.

In yesteryears, you'd go to an ATM, take out the money, then come to the mall, and pay for it. Even earlier, you had a bank check for which you had to go to the bank, withdraw money, and then come back to pay for your expense.

Thanks to the banks, we now have something called a debit card. So now, when you want to purchase something, you present your debit card to the merchant. When you punch in your card details, the money is debited in the merchant's account for your expense.

Let's develop an application in Python v3.5 and implement the above use case. We start with the client first. You went to the shopping mall and now would like to purchase a nice denim shirt. Lets see how Client code is written:

  • Your behavior is represented by the You class—the client
  • To buy the shirt, the make_payment() method is provided by the class
  • The special __init__() method calls the Proxy and instantiates it

[ 54 ]
Chapter 5*

  • The make_payment() method invokes the Proxy's method internally to make the payment
  • The __del__() method returns in case the payment is successful

Thus, the code example is as follows:

class You:

def __init__(self):

print("You:: Lets buy the Denim shirt") self.debitCard = DebitCard()

self.isPurchased = None

def make_payment(self):

self.isPurchased = self.debitCard.do_pay()

def __del__(self):

if self.isPurchased:

print("You:: Wow! Denim shirt is Mine :-)") else:

print("You:: I should earn more :(")

you = You() you.make_payment()

Now let's talk about the Subject class. As we know, the Subject class is an interface that is implemented by the Proxy and RealSubject.

  • In this example, the subject is the Payment class. It is an abstract base class and represents an interface.
  • Payment has the do_pay() method that needs to be implemented by the Proxy and RealSubject.

Let's see these methods in action in the following code:

from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta):

@abstractmethod

def do_pay(self): pass

[ 55 ]
The Proxy Pattern – Controlling Object Access

We also developed the Bank class that represents RealSubject in this scenario:

  • Bank will actually make the payment from your account in the merchant's account.
  • Bank has multiple methods to process the payment. The setCard() method is used by the Proxy to send the debit card details to the bank.
  • The __getAccount() method is a private method of Bank that is used to get the account details of the debit card holder. For simplicity, we have enforced the debit card number to be the same as the account number.
  • Bank also has the __hasFunds() method to see if the account holder has enough funds in the account to pay for the shirt.
  • The do_pay() method that is implemented by the Bank class (from the Payment interface) is actually responsible for making the payment to the merchant based on available funds:

class Bank(Payment):

def __init__(self):

self.card = None

self.account = None

def __getAccount(self):

self.account = self.card # Assume card number is account number

return self.account

def __hasFunds(self):

print("Bank:: Checking if Account", self.__getAccount(), "has enough funds")

return True

def setCard(self, card): self.card = card

def do_pay(self):

if self.__hasFunds():

print("Bank:: Paying the merchant")

return True

else:

print("Bank:: Sorry, not enough funds!") return False

[ 56 ]
Chapter 5*

Let's now understand the last piece, which is the Proxy:

  • The DebitCard class is the Proxy here. When You wants to make a payment, it calls the do_pay() method. This is because You doesn't want go to the bank to withdraw money and pay the merchant.
  • The DebitCard class acts as a surrogate for the RealSubject, Bank.
  • The payWithCard() method internally controls the object creation of RealSubject, the Bank class, and presents the card details to Bank.
  • Bank goes through the internal checks on the account and does the payment, as described in previous code snippet:

class DebitCard(Payment):

def __init__(self):

self.bank = Bank()

def do_pay(self):

card = input("Proxy:: Punch in Card Number: ") self.bank.setCard(card)

return self.bank.do_pay()

For a positive case, when funds are enough, the output is as follows:

For a negative case—insufficient funds—the output is as follows:

[ 57 ]
The Proxy Pattern – Controlling Object Access

Advantages of the Proxy pattern

As we've seen how the Proxy pattern works in the real world, let's browse through the advantages of the Proxy pattern:

  • Proxies can help improve the performance of the application by caching heavy objects or, typically, the frequently accessed objects
  • Proxies also authorize the access to RealSubject; thus, this pattern helps in delegation only if the permissions are right
  • Remote proxies also facilitate interaction with remote servers that can work as network connections and database connections and can be used to monitor systems

Comparing the Façade and Proxy patterns

Both the façade and proxy patterns are structural design patterns. They are similar in the sense that they both have a proxy/façade object in front of the real objects. Differences are really in the intent or purpose of the patterns, as shown in the following table:

Proxy pattern Façade pattern
It provides you with a surrogate or placeholder for another object to control access to it It provides you with an interface to large subsystems of classes
A Proxy object has the same interface as that of the target object and holds references to target objects It minimizes the communication and dependencies between subsystems
It acts as an intermediary between the client and object that is wrapped A Façade object provides a single, simplified interface
Frequently asked questions

Q1. What is the difference between the Decorator pattern and Proxy pattern?

A: A Decorator adds behavior to the object that it decorates at runtime, while a Proxy controls access to an object. The relationship between Proxy and RealSubject is at compile time and not dynamic.

[ 58 ]
Chapter 5*

Q2. What are the disadvantages of the Proxy pattern?

A: The Proxy pattern can increase the response time. For instance, if the Proxy is not well-architectured or has some performance issues, it can add to the response time of RealSubject. Generally, it all depends on how well a Proxy is written.

Q3. Can the client access RealSubject independently?

A: Yes, but there are certain advantages that Proxies provide such as virtual, remote, and others, so it's advantageous to use the Proxy pattern.

Q4. Does the Proxy add any functionality of its own?

A: A Proxy can add additional functionality to RealSubject without changing the object's code. Proxy and RealSubject would implement the same interface.

Summary

We began the chapter by understanding what Proxies are. We understood the basics of a Proxy and how it is used effectively in software architecture. You then learned about the Proxy design pattern and the context in which it's used. We looked at how the Proxy design patterns control access to the real object that provides the required functionality.

We also saw the pattern with a UML diagram and sample code implementation in Python v3.5.

Proxy patterns are implemented in four different ways: virtual proxy, remote proxy, protective proxy, and smart proxy. You learned about each of these with a real-world scenario.

We compared the Façade and Proxy design patterns so that the difference between their use cases and intentions are clear to you.

We also covered a section on FAQs that would help you get more ideas on the pattern and its possible advantages/disadvantages.

At the end of this chapter, we're now geared up to learn more Structural patterns in the chapters to come.

[ 59 ]

'Learning Python Design Patterns' 카테고리의 다른 글

The Façade Pattern  (0) 2023.03.29
The Factory Pattern  (0) 2023.03.29
The Singleton Design Pattern  (0) 2023.03.29
Introduction to Design Patterns  (0) 2023.03.29
Index  (0) 2023.03.29

댓글