Proxy Pattern

Each application has different architecture to it. Architecture can vary based on functionality, extension, flexibility, and infrastructure. Programming for certain domains can require a certain approach. For instance, notice how a typical web application can be different from desktop application. Even without knowing the logic and purpose of the application, we know that they will be designed differently, because web application is accessed over the network by sending requests to the server, and then receiving response. Whereas, the desktop application might or might not do that.

Now imagine that we need to create an application where you can collect real time information about computer, like CPU data, various parts temperature, performance metrics and so on. While we can do that on our local computer with no problem, if we want to be able to get that kind of information from other computers , we will need to devise a better plan. Plus, we also need to consider questions like extension: will we be able to extend this application easily to other channels, like Internet, Ethernet, or reading information through another application? This is a very important aspect as we do not want to come to a situation of stale mate, where we cannot do anything either because code is too complicated, or too many changes need to be made.

Good there is a design pattern that deals with just that – the Proxy Pattern. We will take a look at the definition and then try to dissect what all of that means.


The Proxy Pattern

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


We are going to talk a little about something called a remote proxy. Remote proxy is a local representative of a remote object. The catch is that a client perceives it just like a regular object that it expects. For example, in our real time computer information gathering application he client expects ComputerInfo object. A proxy will present itself as one, so that client will have no idea that it deals with just representation of one. A client can still call its methods and perform all exactly same operations on the proxy because it implements the same interface or extends the same abstract class. What’s special about proxy then? Well, it appears to be an object to the client, however on the inside it handles all of the low-level connections and the whole process of data retrieval from the actual object that is located somewhere else. Our proxy’s methods turn out to be remote methods. These remote methods contact the remote location for the real object to present its data. Once the proxy receives the data, it presents it in front of the client who still thinks that this is the object that it talks to.

In actuality, the low-level communication is often times handled by a couple of extra helper classes. Thus, proxy is communicating with a client helper, which in turn communicates with remote helper, which in turn delivers the message to the remote object. And then the information goes back the same way it came.

// Example in PHP
// Source: https://en.wikipedia.org/wiki/Proxy_pattern
<?php 

interface Image {
    public function displayImage();
}

// On System A
class RealImage implements Image {

    private $filename = null;
    /**
     * Constructor
     * @param $filename
     */
    public function __construct($filename) {
        $this->filename = $filename;
        $this->loadImageFromDisk();
    }

    /**
     * Loads the image from the disk
     */
    private function loadImageFromDisk() {
        echo "Loading {$this->filename} \r\n";
    }

    /**
     * Displays the image
     */
    public function displayImage() {
    	echo "Displaying {$this->filename} \r\n";
    }

}

// On System B
class ProxyImage implements Image {

    private $image = null;
    private $filename = null;
    /**
     * Constructor
     * @param $filename
     */
    public function __construct($filename) {
        $this->filename = $filename;
    }

    /**
     * Displays the image
     */
    public function displayImage() {
        if ($this->image == null) {
           $this->image = new RealImage($this->filename);
        }
        $this->image->displayImage();
    }

}


$image1 = new ProxyImage("HiRes_10MB_Photo1");
$image2 = new ProxyImage("HiRes_10MB_Photo2");

$image1->displayImage(); // loading necessary
$image1->displayImage(); // loading unnecessary
$image2->displayImage(); // loading necessary
$image2->displayImage(); // loading unnecessary
$image1->displayImage(); // loading unnecessary

If you are coding in Java, there is already existing infrastructure to help you deal with that. It is called Java RMI (Remote Method Invocation). RMI builds a client and remote helper objects with exactly the same methods that remote object has. RMI already provides all low-level communication handling, so there is not trouble implementing it. Using RMI, client can call remote methods just like the normal methods. One note to make here is that unlike dealing with a local object directly, remote methods are handled over the network, and therefore are prone to fail often times. Exceptions should be properly handled.

// Example in Java (no RMI)
// Source: https://en.wikipedia.org/wiki/Proxy_pattern
interface Image {
    public void displayImage();
}

// On System A
class RealImage implements Image {
    private final String filename;

    /**
     * Constructor
     * @param filename
     */
    public RealImage(String filename) {
        this.filename = filename;
        loadImageFromDisk();
    }

    /**
     * Loads the image from the disk
     */
    private void loadImageFromDisk() {
        System.out.println("Loading   " + filename);
    }

    /**
     * Displays the image
     */
    public void displayImage() {
        System.out.println("Displaying " + filename);
    }
}

// On System B
class ProxyImage implements Image {
    private final String filename;
    private RealImage image;
    
    /**
     * Constructor
     * @param filename
     */
    public ProxyImage(String filename) {
        this.filename = filename;
    }

    /**
     * Displays the image
     */
    public void displayImage() {
        if (image == null) {
           image = new RealImage(filename);
        }
        image.displayImage();
    }
}

class ProxyExample {
   /**
    * Test method
    */
   public static void main(final String[] arguments) {
        Image image1 = new ProxyImage("HiRes_10MB_Photo1");
        Image image2 = new ProxyImage("HiRes_10MB_Photo2");

        image1.displayImage(); // loading necessary
        image1.displayImage(); // loading unnecessary
        image2.displayImage(); // loading necessary
        image2.displayImage(); // loading unnecessary
        image1.displayImage(); // loading unnecessary
    }
}

Remote proxies are only one way to use the Proxy pattern. This pattern can also be used to create a representative object that controls access to another object, which can be expensive to create or in need of securing. They are called Virtual proxy and Protection proxy respectively. Virtual proxy represents an object that is expensive to create. What it does is deferring the creation of the object until it is requested. You can recognize a little bit of lazy loading in here. After the object is created, the proxy delegates requests to the real object. The Protection proxy acts differently. It is implemented in order to protect an access to it based on predefined set of access rights. This proxy can allow or prohibit calling of certain methods on an object. You can imagine how much it can be used in authorization area.

In fact, there are more uses of the Proxy pattern out there: caching, firewalls, synchronization, complexity hiding, and others. The goal of the pattern stays the same: isolate some kind of complexity, whether it is low-level communication, authorization, or cost of instantiation.

Leave a comment