© Vaskaran Sarcar 2019
Vaskaran SarcarJava Design Patternshttps://doi.org/10.1007/978-1-4842-4078-6_6

6. Proxy Pattern

Vaskaran Sarcar1 
(1)
Bangalore, Karnataka, India
 

This chapter covers the proxy pattern.

GoF Definition

Provide a surrogate or placeholder for another object to control access to it.

Concept

A proxy is basically a substitute for an intended object. Access to the original object is not always possible due to many factors. For example, it is expensive to create, it is in need of being secured, it resides in a remote location, and so forth. The proxy design pattern helps us in similar contexts. When a client deals with a proxy object, it assumes that it is talking to the actual object. So, in this pattern, you may want to use a class that can perform as an interface to something else.

Real-World Example

In a classroom, when a student is absent, his best friend may try to mimic his voice during roll call to try to get attendance for his friend.

Computer-World Example

In the programming world, to create multiple instances of a complex object (heavy object) is costly . So, whenever you are in need, you can create multiple proxy objects that point to the original object. This mechanism can also help save your system/application memory. An ATM can implement this pattern to hold proxy objects for bank information that may exist on a remote server.

Note

In the java.lang.reflect package, you can have a Proxy class and an InvocationHandler interface that supports a similar concept. The java.rmi.* package also provides methods through which an object on one Java virtual machine can invoke methods on an object that resides in a different Java virtual machine.

Illustration

In the following program, I am calling the doSomework() method of the proxy object, which in turn, calls the doSomework() method of an object of ConcreteSubject. When clients see the output, they do not know that the proxy object does the trick.

Class Diagram

Figure 6-1 shows the class diagram.
../images/395506_2_En_6_Chapter/395506_2_En_6_Fig1_HTML.jpg
Figure 6-1

Class diagram

Package Explorer View

Figure 6-2 shows the high-level structure of the program.
../images/395506_2_En_6_Chapter/395506_2_En_6_Fig2_HTML.jpg
Figure 6-2

Package Explorer view

Implementation

Here’s the implementation.
package jdp2e.proxy.demo;
// Abstract class Subject
abstract class Subject
{
      public abstract void doSomeWork();
}
// ConcreteSubject class
class ConcreteSubject extends Subject
{
      @Override
      public void doSomeWork()
      {
            System.out.println("doSomeWork() inside ConcreteSubject is invoked.");
      }
}
/**
 * Proxy Class: It will try to invoke the doSomeWork()
 * of a ConcreteSubject instance
 */
Class Proxy extends  Subject
{
      static Subject cs;
      @Override
      public void doSomeWork()
      {
            System.out.println("Proxy call happening now...");
            //Lazy initialization:We'll not instantiate until the method is //called
            if (cs == null)
            {
                   cs = new ConcreteSubject();
            }
            cs.doSomeWork();
      }
}
/**
 * The client is talking to a ConcreteSubject instance
 * through a proxy method.
 */
public class ProxyPatternExample {
      public static void main(String[] args) {
            System.out.println("***Proxy Pattern Demo*** ");
            Proxy px = new Proxy();
            px.doSomeWork();
      }
}

Output

Here’s the output.
***Proxy Pattern Demo***
Proxy call happening now...
doSomeWork() inside ConcreteSubject is invoked.

Q&A Session

  1. 1.

    What are the different types of proxies?

    These are the common types:
    • Remote proxies . Hide the actual object that stays in a different address space.

    • Virtual proxies . Perform optimization techniques, such as the creation of a heavy object on a demand basis.

    • Protection proxies . Deal with different access rights.

    • Smart reference . Performs additional housekeeping work when an object is accessed by a client. A typical operation is counting the number of references to the actual object at a particular moment.

     
  2. 2.
    You could create the ConcreteSubject instance in the proxy class constructor, as follows.
    class Proxy extends  Subject
    {
          static Subject cs;
          public Proxy()
          {
                //Instantiating inside the constructor
                cs = new ConcreteSubject();
          }
          @Override
          public void doSomeWork()
          {
                System.out.println("Proxy call happening now...");
                cs.doSomeWork();
          }
    }

    Is this correct?

    Yes, you could do that. But if you follow this design, whenever you instantiate a proxy object, you need to instantiate an object of the ConcreteSubject class also. So, this process may end up creating unnecessary objects. You can simply test this with the following piece of code and the corresponding outputs.

     

Alternate Implementation

Here’s the alternative implementation.
package jdp2e.proxy.questions_answers;
//Abstract class Subject
abstract class Subject
{
      public abstract void doSomeWork();
}
//ConcreteSubject class
class ConcreteSubject extends Subject
{
      @Override
      public void doSomeWork()
      {
            System.out.println("doSomeWork() inside ConcreteSubject is invoked");
      }
}
/**
 * Proxy Class
 * It will try to invoke the doSomeWork() of a ConcreteSubject instance *
 */
class Proxy extends  Subject
{
      static Subject cs;
      static int count=0;//A counter to track the number of instances
      public Proxy()
      {
            //Instantiating inside the constructor
            cs = new ConcreteSubject();
            count ++;
      }
      @Override
      public void doSomeWork()
      {
            System.out.println("Proxy call happening now...");
            //Lazy initialization:We'll not instantiate until the method is //called
            /*if (cs == null)
            {
                   cs = new ConcreteSubject();
                   count ++;
             }*/
             cs.doSomeWork();
      }
}
/**
  * The client is talking to a ConcreteSubject instance
 * through a proxy method.
 */
public class ProxyPatternQuestionsAndAnswers {
      public static void main(String[] args) {
             System.out.println("***Proxy Pattern Demo without lazy instantiation*** ");
             //System.out.println("***Proxy Pattern Demo with lazy instantiation*** ");
             Proxy px = new Proxy();
             px.doSomeWork();
             //2nd proxy instance
             Proxy px2 = new Proxy();
             px2.doSomeWork();
             System.out.println("Instance Count="+Proxy.count);
      }
}

Output Without Lazy Instantiation

Here’s the output.
***Proxy Pattern Demo without lazy instantiation***
Proxy call happening now...
doSomeWork() inside ConcreteSubject is invoked
Proxy call happening now...
doSomeWork() inside ConcreteSubject is invoked
Instance Count=2

Analysis

Notice that you have created two proxy instances.

Now, try our earlier approach with lazy instantiation. (Remove the proxy constructor and uncomment the lazy instantiation stuffs).

Output with Lazy Instantiation

Here’s the output.
***Proxy Pattern Demo with lazy instantiation***
Proxy call happening now...
doSomeWork() inside ConcreteSubject is invoked
Proxy call happening now...
doSomeWork() inside ConcreteSubject is invoked
Instance Count=1

Analysis

Notice that you have created only one proxy instance this time.
  1. 3.

    But in this lazy instantiation technique , you may create unnecessary objects in a multithreaded application. Is this correct?

    Yes. In this book, I am presenting simple illustrations only, so I have ignored that part. In the discussions on the singleton pattern, I analyzed some alternative approaches to deal with a multithreaded environment. You can always refer to those discussions in situations like this. (For example, in this particular scenario, you can implement a synchronization technique, or a locking mechanism, or a smart proxy, and so forth to ensure that a particular object is locked before you grant access to the object.)

     
  2. 4.

    Can you give an example of a remote proxy?

    Suppose, you want to call a method of an object but the object is running in a different address space (e.g., different locations or different computers, etc.). How do you proceed? With the help of remote proxies, you can call the method on the proxy object, which in turn forwards the call to the actual object that is running on the remote machine. This type of need can be realized through well-known mechanisms like ASP.NET, CORBA, C#’s WCF (version 3.0 onward), or Java’s RMI (Remote Method Invocation).

    Figure 6-3 demonstrates a simple remote proxy structure.
    ../images/395506_2_En_6_Chapter/395506_2_En_6_Fig3_HTML.jpg
    Figure 6-3

    A simple remote proxy diagram

     
  3. 5.

    When can you use a virtual proxy?

    It can be used to avoid multiple loadings of an extremely large image.

     
  4. 6.

    When can you use a protection proxy?

    The security team in an organization can implement a protection proxy to block Internet access to specific websites.

     

Consider the following example, which is basically a modified version of the proxy pattern implementation described earlier. For simplicity, let’s assume that at present, we have only three registered users who can exercise the doSomeWork() proxy method. Apart from them, if any other user (say, Robin) tries to invoke the method, the system will reject those attempts. You must agree, when the system will reject this kind of unwanted access; there is no point in making a proxy object. So, if you avoid instantiating an object of ConcreteSubject in the Proxy class constructor, you can easily avoid these kinds of additional objects creation.

Now go through the modified implementation.

Modified Package Explorer View

Figure 6-4 shows the modified high-level structure of the program.
../images/395506_2_En_6_Chapter/395506_2_En_6_Fig4_HTML.jpg
Figure 6-4

Modified Package Explorer view

Modified Implementation

Here’s the modified implementation.
package jdp2e.proxy.modified.demo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//Abstract class Subject
abstract class Subject
{
       public abstract void doSomeWork();
}
//ConcreteSubject class
class ConcreteSubject extends Subject
{
       @Override
       public void doSomeWork()
       {
              System.out.println("doSomeWork() inside ConcreteSubject is invoked.");
       }
}
/**
 * Proxy Class:It will try to invoke the doSomeWork()
 * of a ConcreteSubject instance
 */
class ModifiedProxy extends  Subject
{
       static Subject cs;
       String currentUser;
       List<String> registeredUsers;
       //Or, simply create this mutable list in one step
       /*List<String> registeredUsers=new ArrayList<String>(Arrays.asList( "Admin","Rohit","Sam"));*/
       public ModifiedProxy(String currentUser)
       {
              //Registered users are Admin, Rohit and Sam only .
              registeredUsers = new ArrayList<String>();
              registeredUsers.add("Admin");
              registeredUsers.add("Rohit");
              registeredUsers.add("Sam");
              this.currentUser = currentUser;
       }
       @Override
       public void doSomeWork()
       {
              System.out.println(" Proxy call happening now...");
              System.out.println(currentUser+" wants to invoke a proxy method.");
              if (registeredUsers.contains(currentUser))
              {
                     //Lazy initialization:We'll not instantiate until the
                     //method is called
                     if (cs == null)
                     {
                            cs = new ConcreteSubject();
                     }
                     //Allow the registered user to invoke the method
                     cs.doSomeWork();
              }
              else
              {
                     System.out.println("Sorry "+ currentUser+ " , you do not have access rights.");
              }
       }
}
/**
 * The client is talking to a ConcreteSubject instance
 * through a proxy method.
 */
public class ModifiedProxyPatternExample {
       public static void main(String[] args) {
              System.out.println("***Modified Proxy Pattern Demo*** ");
              //Admin is an authorized user
              ModifiedProxy px1 = new ModifiedProxy("Admin");
              px1.doSomeWork();
              //Robin is an unauthorized user
              ModifiedProxy px2 = new ModifiedProxy("Robin");
              px2.doSomeWork();
       }
}

Modified Output

Here’s the modified output.
***Modified Proxy Pattern Demo***
Proxy call happening now...
Admin wants to invoke a proxy method.
doSomeWork() inside ConcreteSubject is invoked.
Proxy call happening now...
Robin wants to invoke a proxy method.
Sorry Robin, you do not have access rights.
  1. 7.

    Proxies act like decorators. Is this correct?

    You can implement a protection proxy similar to decorators but you should not forget the intent. Decorators focus on adding responsibilities, but proxies focus on controlling the access to an object. Proxies differ from each other with their types and implementations. Also, in general, proxies work on the same interface but decorators can work on extended interfaces. So, if you can remember their purposes, in most cases, you can clearly distinguish them from decorators.

     
  2. 8.

    What are the cons associated with proxies?

    If you are careful enough in your implementation, the pros are much greater than the cons, but
    • You can raise your concern about the response time. Since you are not directly talking to the actual object, it is possible that the response time through these proxies is longer.

    • You need to maintain additional code for the proxies.

    • A proxy can hide the actual responses from objects, which may create confusion in special scenarios.

     
..................Content has been hidden....................

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