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
  • 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

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

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:

The Proxy pattern in the real world

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

The Proxy pattern in the real world
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.33.157