Proxy pattern

From Wikipedia, the free encyclopedia

Jump to: navigation, search
Proxy in UML
Proxy in LePUS3 (legend)

In computer programming, the proxy pattern is a software design pattern.

A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.

A well-known example of the proxy pattern is a reference counting pointer object.

In situations where multiple copies of a complex object must exist the proxy pattern can be adapted to incorporate the Flyweight Pattern in order to reduce the application's memory footprint. Typically one instance of the complex object is created, and multiple proxy objects are created, all of which contain a reference to the single original complex object. Any operations performed on the proxies are forwarded to the original object. Once all instances of the proxy are out of scope, the complex object's memory may be deallocated.

Contents

[edit] Examples

[edit] Java

The following Java example illustrates the "virtual proxy" pattern. The ProxyImage class is used to delay the expensive operation of loading a file from disk until the result of that operation is actually needed. If the file is never needed, then the expensive load has been totally eliminated.

import java.util.*;
 
interface Image {
    public void displayImage();
}
 
class RealImage implements Image {
    private String filename;
    public RealImage(String filename) { 
        this.filename = filename;
        loadImageFromDisk();
    }
 
    private void loadImageFromDisk() {
        // Potentially expensive operation
        // ...
        System.out.println("Loading   "+filename);
    }
 
    public void displayImage() { 
        System.out.println("Displaying "+filename); 
    }
}
 
class ProxyImage implements Image {
    private String filename;
    private Image image;
 
    public ProxyImage(String filename) { 
        this.filename = filename; 
    }
    public void displayImage() {
        if (image == null) {
            image = new RealImage(filename); // load only on demand
        }
        image.displayImage();
    }
}
 
class ProxyExample {
    public static void main(String[] args) {
        Image image1 = new ProxyImage("HiRes_10MB_Photo1");
        Image image2 = new ProxyImage("HiRes_10MB_Photo2");
        Image image3 = new ProxyImage("HiRes_10MB_Photo3");      
 
        image1.displayImage(); // loading necessary
        image2.displayImage(); // loading necessary
        image1.displayImage(); // no loading necessary; already done
        // the third image will never be loaded - time saved!
    }
}

The program's output is:

Loading    HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading    HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo1

[edit] Python

#!/opt/env/python
 
class Image(object):
	def display(self):
		pass
 
class RealImage(Image):
	def __init__(self, name):
		self.name = name
		self.load()
	def load(self):
		print "Loading...", self.name
	def display(self):
		print "Displaying...", self.name
 
class ProxyImage(Image):
	def __init__(self, name):
		self.name = name
		self.test = None
	def display(self):
		if self.test is None:
			self.test = RealImage(self.name)
		self.test.display()
 
def main():
	t1 = ProxyImage("big_image1.png")
	t2 = ProxyImage("big_image2.png")
	t3 = ProxyImage("big_image3.png")
 
	t1.display() # loads, displays
	t2.display() # loads, displays
	t1.display() # displays
#	t3.display() # no display, no load
	return
 
if __name__ == "__main__":
	main()

[edit] C#

In this C# example, the RealClient stores an account number. Only users who know a valid password can access this account number. The RealClient is protected by a ProtectionProxy which knows the password. If a user wants to get an account number, first the proxy asks the user to authenticate; only if the user entered a correct password does the proxy invoke the RealClient to get an account number for the user.

In this example, thePassword is the correct password.

using System;
 
namespace ConsoleApplicationTest.FundamentalPatterns.ProtectionProxyPattern
{
    public interface IClient {
        string GetAccountNo();
    }
 
    public class RealClient : IClient {
        private string accountNo = "12345";
        public RealClient() {
            Console.WriteLine("RealClient: Initialized");
        }
        public string GetAccountNo() {
            Console.WriteLine("RealClient's AccountNo: {0}", accountNo);
            return accountNo;
        }
    }
 
 
    public class ProtectionProxy : IClient
    {
        private string password;  //password to get secret
        RealClient client;
 
        public ProtectionProxy(string pwd) {
            Console.WriteLine("ProtectionProxy: Initialized");
            password = pwd;
            client = new RealClient();
        }
 
        // Authenticate the user and return the Account Number
        public String GetAccountNo() {
            Console.Write("Password: ");
            string tmpPwd = Console.ReadLine();
 
            if (tmpPwd == password) {
                return client.GetAccountNo();
            } else {
                Console.WriteLine("ProtectionProxy: Illegal password!");
                return "";
            }
        }
    }
 
    class ProtectionProxyExample
    {
        [STAThread]
        public static void Main(string[] args) {
            IClient client = new ProtectionProxy("thePassword");
            Console.WriteLine();
            Console.WriteLine("main received: {0}", client.GetAccountNo());
            Console.WriteLine("\nPress any key to continue . . .");
            Console.Read();
        }
    }
}

[edit] C++

#include <string>
#include <iostream>
 
class Image //abstract
{
protected:
   Image() {}
 
public:
   virtual ~Image() {}
 
   virtual void displayImage() = 0;
};
 
class RealImage : public Image
{
public:
   explicit RealImage(std::string filename)
   {
      this->filename = filename;
      loadImageFromDisk();
   }
 
 
   void displayImage()
   {
      std::cout<<"Displaying "<<filename<<std::endl;
   }
 
private:
   void loadImageFromDisk()
   {
      // Potentially expensive operation
      // ...
      std::cout<<"Loading    "<<filename<<std::endl;
   }
 
   std::string filename;
};
 
class ProxyImage : public Image
{
public:
   explicit ProxyImage(std::string filename)
   {
      this->filename = filename;
      this->image = nullptr;
   }
   ~ProxyImage() { delete image; }
 
   void displayImage()
   {
      if (image == nullptr) {
         image = new RealImage(filename); // load only on demand
      }
 
      image->displayImage();
   }
 
private:
   std::string filename;
   Image* image;
};
 
int main(int argc, char* argv[])
{
   std::cout<<"main"<<std::endl;
 
   Image* image1 = new ProxyImage("HiRes_10MB_Photo1");
   Image* image2 = new ProxyImage("HiRes_10MB_Photo2");
   Image* image3 = new ProxyImage("HiRes_10MB_Photo3");      
 
   image1->displayImage(); // loading necessary
   image2->displayImage(); // loading necessary
   image1->displayImage(); // no loading necessary; already done
   // the third image will never be loaded - time saved!
 
   delete image1;
   delete image2;
   delete image3;
 
   return 0;
}

[edit] Perl

The Perl with Moose implementation. The "lazy" option is used to delay the expensive operation. The "handles" option is used to create the delegation to proxied class.

use MooseX::Declare;
 
role Image {
    requires 'display_image';
}
 
class RealImage with Image {
    has 'filename' => (
        isa => 'Str',
    ); 
 
    # Moose's constructor
    method BUILD ($params) {
        $self->_load_image_from_disk;
    }
 
    method _load_image_from_disk () {
        # Expensive operation
        print "Loading   " . $self->{filename} . "\n";
    }
 
    method display_image () {
        print "Displaying " . $self->{filename} . "\n";
    }
}
 
class ProxyImage with Image {
    has 'filename' => (
        isa => 'Str',
    ); 
    has 'image' => (
        does => 'Image',
        lazy => 1,  # default value is loaded only on demand
        default => sub { RealImage->new( filename => $_[0]->{filename} ) },
        handles => [ 'display_image' ],  # automatic delegation
    );
}
 
class ProxyExample {
    # Moose's constructor
    method BUILD ($params) {
        my $image1 = ProxyImage->new( filename=>'HiRes_10MB_Photo1' );
        my $image2 = ProxyImage->new( filename=>'HiRes_10MB_Photo2' );
        my $image3 = ProxyImage->new( filename=>'HiRes_10MB_Photo3' );
 
        $image1->display_image;  # loading necessary
        $image2->display_image;  # loading necessary 
        $image1->display_image;  # already done
        # the third image will never be loaded - time saved!
    }
}
 
ProxyExample->new;


[edit] ActionScript

package
{
	import flash.display.Sprite;
 
	public class ProxyExample extends Sprite
	{
		public function ProxyExample()
		{
			var image1:Image = new ProxyImage("HiRes_10MB_Photo1");
			var image2:Image = new ProxyImage("HiRes_10MB_Photo2");
			var image3:Image = new ProxyImage("HiRes_10MB_Photo3");
 
			image1.displayImage();// loading necessary
			image2.displayImage();// loading necessary
			image1.displayImage();// no loading necessary; already done
			// the third image will never be loaded - time saved!
		}
	}
}
interface Image
{
	function displayImage():void;
}
 
class RealImage implements Image
{
	private var filename:String;
	public function RealImage(filename:String)
	{
		this.filename = filename;
		loadImageFromDisk();
	}
	private function loadImageFromDisk():void
	{
		// Potentially expensive operation
		// ...
		trace("Loading	", filename);
	}
 
	public function displayImage():void
	{
		trace("Displaying	", filename);
	}
}
 
class ProxyImage implements Image
{
	private var filename:String;
	private var image:Image;
 
	public function ProxyImage(filename:String)
	{
		this.filename = filename;
	}
 
	public function displayImage():void
	{
		if ( image == null )
		{
			image = new RealImage(filename); // load only on demand
		}
		image.displayImage();
	}
}

[edit] See also

[edit] External links


Personal tools