Design patterns: Proxy

in #design-patterns6 years ago

1_DjWCgTFm-xqbhbNQVsaWQw.png

The proxy pattern is quite similar to the Bridge pattern, but the purpose of the Proxy is different, its purpose is to create an object that will represent another object, so in a nutshell, more precisely about this pattern further. I will try to present the majority of examples in several languages m.i.n in C ++, Java, C # and python, there will be a link to github at the end of the entry.

Intent

  1. Controls access to classes and its objects, indirectly through a different class and objects.
  2. Creates packaging for classes to protect them from excessive complexity.
  3. It creates objects (usually those that eat up a lot of processor resources) when they are really needed.

Problem

You need to create some resource-consuming objects, but you do not want to create their instances quickly. A proxy will be useful here.

Or another example, you want to create a class, but it must be well-encapsulated and controlled, such a class may, for example, represent a system of making transfers in the bank system.

Use when:

  1. You want to create an object that is expensive to create, then use a virtual proxy that will create the object on demand.
  2. You want to have limited access to the facility, e.g. on a password
  3. You want to create an object that will represent objects in a different address space, eg it can be a proxy class that uses data stored on another server for operation.

Structure

Below the UML diagram of the proxy pattern, it can be seen that only in the proxy class we create a real object.

Proxy1.png

Example

Below is the schema of the proxy pattern in the code, it looks more or less that:

namespace Proxy
{
    interface ExampleInterface
    {
        void DoSomeThing();
    }
 
    class ExampleClass : ExampleInterface
    {
        public void DoSomeThing()
        {
            Console.WriteLine("Do something");
        }
    }
 
    class Proxy : ExampleInterface
    {
        private ExampleInterface exampleClass;
        private string password { get; set; }
 
        public Proxy(string password)
        {
            this.password = password;
        }
 
        private void CreateInstanceExampleClass()
        {
            exampleClass = new ExampleClass();
        }
 
        public void DoSomeThing()
        {
            if (password == "root")
            {
                CreateInstanceExampleClass();
                exampleClass.DoSomeThing();
            }
            else
            {
                Console.WriteLine("Wrong password");
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            string password = Console.ReadLine();
 
            Proxy proxy = new Proxy(password);
            proxy.DoSomeThing();
 
            Console.ReadKey();
        }
    }
}

When we run this program, we must enter the correct password in the console, in this case it is root, if we type it we create a class object, in this pattern we create the object when we need it, so we do not do it through Dependency Injection, but we created for it a special method that creates this object, when we enter the correct password, you can create a factory in this pattern so that class instances are well-encapsulated but in this simple example we will not play with it.

Result

ProxyExample.png

An example of life taken

We will make an example on the principle of making transfers in the banking system, you can withdraw money on the basis of a bank card from the bank and thanks to it we can control how much money we have in the bank, how much we want to pay out, etc. This is shown in the picture below:

Proxy_example1.png

Let’s see how it looks in the code:

namespace CartbankC
{
    interface IPayment
    {
        double CheckStateAccount();
        void PayOutMoneyFromAccount(double AmountPayedOutMoney);
    }
 
    class BankAccount : IPayment
    {
        private double StateMyAccount = 10000;
 
        public double CheckStateAccount()
        {
            return StateMyAccount;
        }
 
        public void PayOutMoneyFromAccount(double AmountPayedOutMoney)
        {
            StateMyAccount = StateMyAccount - AmountPayedOutMoney;
        }
    }
 
    abstract class PaymentFactory
    {
        public abstract IPayment Bank();
    }
 
    class BankAccountFactory : PaymentFactory
    {
        public override IPayment Bank()
        {
            return new BankAccount();
        }
    }
 
    class CartBank : IPayment
    {
        IPayment BankAccount;
        private int PIN;
        public bool IfPinIsValid;
 
        public void getPIN(int pin)
        {
            PIN = pin;
            CheckPinIsValid();
        }
 
        private void CheckPinIsValid()
        {
            if (PIN == 1223)
            {
                OpenAccessToAccount();
                IfPinIsValid = true;
            }
            else
            {
                IfPinIsValid = false;
            }
        }
 
        private void OpenAccessToAccount()
        {
            PaymentFactory paymentfactory = new BankAccountFactory();
 
            BankAccount = paymentfactory.Bank();
        }
 
        public double CheckStateAccount()
        {
            return BankAccount.CheckStateAccount();
        }
 
        public void PayOutMoneyFromAccount(double AmountPayedOutMoney)
        {
            BankAccount.PayOutMoneyFromAccount(AmountPayedOutMoney);
        }
    }
 
    
    class Program
    {
        static void Main(string[] args)
        {
            int pin = int.Parse(Console.ReadLine());
 
            CartBank cartbank = new CartBank();
            cartbank.getPIN(pin);
 
            if (cartbank.IfPinIsValid)
            {
                Console.WriteLine("The correct pin has been entered, what do you want to do?");
                Console.WriteLine("Withdraw 4,000 USD from the bank");
                cartbank.PayOutMoneyFromAccount(4000);
                Console.WriteLine("You have: " + cartbank.CheckStateAccount() + " USD left in your account");
            }
            else
            {
                Console.WriteLine("Incorrect pin entered, try again");
            }
 
            Console.ReadKey();
        }
    }
}

It is long this example, but I think that it shows well action an proxy pattern.

I attributed $ 10,000 to our account 🙂 (it’s a pity that it’s just fairytale money 😥😥 )

As you can see first, the client enters a pin and then the proxy class checks if it is correct ✅, if it’s correct, it opens access to the account, in our example it appears in the form of the BankAccount class object using the factory pattern.

And we set the values true, false depending on whether the pin is correct. And finally, in the client if the pin is correct ✅ then we call the methods of the BankAccount class, if not ❌ then we only display the appropriate message.

Result

Cartbank.png

Relations with design patterns

  1. The adapter provides a different interface for the object. Proxy provides the same interface. The decorator provides an extended interface.
  2. The decorator and proxy have different goals, but similar structures. Both describe how to provide an intermediate level to another object, and implementations retain a reference to the object to which they send requests.

Summary

That’s all about Proxy 🙂.

Link to github with the whole code from this article: https://github.com/Slaw145/ProxyTutorial

This content also you can find on my blog http://devman.pl/programtech/design-patterns-proxy/

If you recognise it as useful, share it with others so that others can also use it.

Leave upvote and follow and wait for next articles :) .

In the next article, we will talk about the Flyweight pattern.

And NECESSERILY join the DevmanCommunity community on fb, part of the community is in one place 🙂

– site on fb: Devman.pl-Sławomir Kowalski

– group on fb: DevmanCommunity

Ask, comment underneath at the end of the post, share it, rate it, whatever you want🙂.

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.034
BTC 63688.35
ETH 3125.30
USDT 1.00
SBD 3.97