Proxy (patró de disseny)

De Viquipèdia
Dreceres ràpides: navegació, cerca
Proxy en UML
Proxy en LePUS3 (llegenda)

En programació, el patró proxy és un patró de disseny de programari.

Un proxy, en la seva forma més general, és una classe que funciona com una interfície a una altra cosa. L'altra cosa podria ser qualsevol: una connexió a la xarxa, un gran objecte en la memòria, un arxiu, o algun altre recurs que és car o impossible de duplicar.

Un exemple ben conegut dels proxys és d'intermediari en un model referenciat amb punters a objectes.

En els casos que hi ha vaires còpies d'un objecte complex el patró proxy pot ser adaptat per incorporar al patró Flyweight per tal de reduir la necessitat de memòria.

Codis d'exemple[modifica | modifica el codi]

Java[modifica | modifica el codi]

El següent exemple en Java implementa el patró "virtual proxy". La sortida del programa és:

Loading    HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading    HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo1

La classe ProxyImage és usada per a retardar la costosa operació de càrrega d'un fitxer des del disc fins que aquesta operació és realment necessària. Si l'arxiu no és necessari, doncs, la costosa càrrega s'ha evitat.

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!
    }
}

Python[modifica | modifica el codi]

#!/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 not self.test:
			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()

C#[modifica | modifica el codi]

En aquest exemple de C #, el RealClient emmagatzema un número de compte. Només els usuaris que coneixen una contrasenya vàlida poden accedir a aquest número de compte. El RealClient està protegit per una ProtectionProxy que sap la contrasenya. Si un usuari vol obtenir un número de compte, en primer lloc, el proxy demana a l'usuari autenticar-se, i només si l'usuari posa una contrasenya correcta el proxy no invoca el RealClient per obtenir un número de compte per a l'usuari.

En aquest exemple, thePassword és la contrasenya correcta.

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: " + 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: " + client.GetAccountNo());
            Console.WriteLine("\nPress any key to continue . . .");
            Console.Read();
        }
    }
}

C++[modifica | modifica el codi]

#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;
}

Perl[modifica | modifica el codi]

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;

Vegeu també[modifica | modifica el codi]

Enllaços externs[modifica | modifica el codi]

A Wikimedia Commons hi ha contingut multimèdia relatiu a: Proxy (patró de disseny) Modifica l'enllaç a Wikidata