Articoli Manifesto Tools Links Canali Libri Contatti ?
Design / Design Patterns

Il Proxy Pattern

Abstract
In questo articolo descriviamo il Proxy Pattern, uno "Structural Pattern" assai usato, semplice e molto potente.
Data di stesura: 08/12/2002
Data di pubblicazione: 20/12/2002
Ultima modifica: 04/04/2006
di Giovanni Giorgi Discuti sul forum   Stampa

Il proxy pattern fornisce un "surrogato" (o segnaposto) per un altro oggetto di cui si desidera controllare l'accesso. Pur trattandosi di un design pattern molto semplice, ne esistono parecchie varianti ed il suo uso si è diffuso a macchia d'olio in diversi contesti.

Come esempio, supponiamo di dover pilotare a distanza il robottino della NASA che esplorò Marte, il Mars Path Finder. Data la distanza, non possiamo controllare in real-time il robot, perché il segnale radio (che viaggia alla velocità della luce) ci impiega parecchie ORE ad arrivare su Marte.

Consideriamo il seguente diagramma UML:

[Figura 1]

Figura 1: Un proxy per il Mars Path Finder

La classe astratta Robot modella il robot, dichiarando i metodi di acceso consentiti. La classe MarsPathFinder implementa il robot vero e proprio, mentre la classe Proxy implementa il proxy, facendo riferimento al vero robot.

Questo tipo di proxy si chiama Remote Proxy e serve appunto a modellare un oggetto che non è direttamente accessibile. Nel nostro caso, il Proxy potrebbe registrare tutti i comandi dati al robot, e simularli su un modello 3D del pianeta. Gli addetti al controllo sarebbero quindi in grado di verificare la correttezza delle operazioni.
Poi, ad intervalli prefissati il Proxy potrebbe mandare una sequenza di comandi al vero robot. Quest'ultimo, una volta ricevuti tutti i comandi, si occuperebbe di eseguirli in rapida successione, in modo da evitare le latenze di comunicazione.

Si osservi come l'attributo realSubject sia dichiarato private all'interno del Proxy, e la necessità del proxy di implementare gli stessi metodi del robot concreto. In generale Proxy deve mantenere il comportamento (Behavior) dell'oggetto astratto Robot, arricchendo la semantica dell'oggetto concreto MarsPathFinder.

I remote proxy sono usati anche in altri contesti, per esempio nell'implementazione dei protocolli distribuiti (CORBA, EJB in primis). Per esempio possono farsi carico degli errori di comunicazione e risolverli a basso livello.

Vi sono due altri tipi di proxy che meritano di essere studiati:

Virtual Proxy Utile ad esempio nei database orientati agli oggetti (OODBMGR).
Security Proxy Permette di dotare degli oggetti di uno strato che garantisca il controllo degli accessi.

Virtual Proxy

Programmando ad oggetti è assai comodo poter usare un database orientato agli oggetti, chiamato OODBMGR. Ma implementare un OODBMGR non è una cosa banale: infatti esso deve avere caratteristiche sensibilmente diverse da un database relazionale.
Supponiamo per esempio di aver memorizzato un albero binario da 23Gb in un database.
Quando carichiamo dal database la radice, possiamo navigare tutto l'albero come vogliamo. Peccato che non abbiamo 23Gb di RAM e che vogliamo soltanto estrarre un percorso di nodi di qualche Kb. Il database ad oggetti allora ci viene in aiuto. Piuttosto che caricare tutto l'albero, esso carica il nodo padre e invece di caricare ricorsivamente i due nodi figli, mette al loro posto due virtual proxy.

I virtual proxy implementano l'interfaccia "Node":

[Figura 2]

Figura 2: Virtual Proxy Node

I virtual proxy contengono un riferimento all'oggetto sul database. Questo riferimento può essere un codice hash univoco (chiamato anche OID, Object IDentifer) e di solito occupa pochissimo spazio.

Supponiamo ora di volere il nodo sinistro del padre. La sequenza di chiamata è la seguente:

[Figura 3]

Figura 3: Sequenza di chiamata dell'OODBMGR

La classe DBMGR_Proxy_Node si serve dei servizi interni al database (contenute in DBMGR_Loader) per caricare l'oggetto, ed invocare su di esso il metodo getLeft(). È compito del database creare un proxy virtuale: in generale questa operazione è fatta all'atto della compilazione dello schema delle classi rese persistenti.
Esistono anche database in grado di inserire oggetti al "volo" creando gli opportuni proxy.

Scambiare un proxy con il vero oggetto

L'OODBMGR può decidere di sostituirci "sotto il naso" il proxy, caricando il vero oggetto e rimpiazzandolo.

In alcuni linguaggi (come SmallTalk) questa operazione è semplice da fare: c'è un metodo apposta (che si chiama become:) che scambia i riferimenti a due oggetti, giocando con il Garbage Collector.

In altri (come in Java e C++) è necessario giocare a bassissimo livello con la gestione dei puntatori agli oggetti o introdurre uno strato di indirettezza in più.

In alcuni database è possibile impostare anche la "profondità di prefetch" degli oggetti. Con tale parametro è possibile decidere come il database userà i proxy virtuali.
Per esempio supponiamo di avere l'oggetto A che ha un riferimento all'oggetto B che ha un riferimento all'oggetto C. Supponiamo inoltre che C faccia riferimento a D ed A.
Se impostiamo nello schema dell'OODMBR una profondità di prefetch pari a due, e carichiamo A, il database caricherà in memoria solo A e B e NON C.
Se accederemo a C il DBMGR caricherà C e D, e imposterà il riferimento da C ad A in modo corretto.

Security Proxy

La sicurezza è un aspetto importante dell'informatica, ma solo verso gli anni 1994-95 si è iniziato a sentirla come una necessità anche presso le applicazioni Web. La diffusione dell'e-commerce e del trading on line ha fatto sì che fosse necessario rafforzare il debole TCP/IP, non pensato per garantire privacy e sicurezza.

Può quindi succedere di trovarsi con dei sistemi legacy "ingenui" a cui sia necessario aggiungere in fretta un modello forte di sicurezza.

Siccome il tempo è sempre poco, il proxy pattern può risultare rapido e efficace per rispettare i requisiti funzionali.

Per esempio è possibile far si che un ACLManager si preoccupi di verificare le credenziali del Client, con un codice del genere (esempio per codice Java):

  1. String username="kevin"; 
  2. String password="oppip"; 
  3. Robot r; 
  4. r = ACLManager.getRobot(username, password); 
  5. r.moveForward(); 
Il Security Proxy può rafforzare i controlli, per esempio potrebbe impedire ad un client certificato, ma senza diritti di supervisione, di invocare il metodo stop().

Conclusioni

L'overhead dovuto all'introduzione del proxy è trascurabile, se si tiene conto dei vantaggi che esso introduce. Inoltre un proxy può essere usato al posto dell'oggetto reale, nel caso esso non sia ancora implementato in modo completo o non sia disponibile: come vedremo un proxy può risultare utile anche per effettuare test di unità e di non regressione (in tal caso si parla di mock objects).

Informazioni sull'autore

Giovanni Giorgi, classe 1974. Dopo il diploma di liceo Classico, si è laureato in Informatica nel febbraio 2000, e attualmente lavora nel campo del software finanziario (trading on line, soluzioni web).
Appassionato di linguaggi di programmazione, si interessa anche di politica e letteratura.

È possibile consultare l'elenco degli articoli scritti da Giovanni Giorgi.

Altri articoli sul tema Design / Design Patterns.

Risorse

  1. I modelli usati in questo articolo (file mdl per Rational Rose).
    http://www.siforge.org/articles/2002/12/proxy-pattern/proxy-model.zip (10Kb)
  2. Descrizione del proxy pattern presso il Portland Pattern Repository
    http://c2.com/cgi/wiki?ProxyPattern
  3. Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides,
    "Design Patterns. Elements of Reusable Object-Oriented Software"
    Ed. Addison Wesley 1994.
    Spesso viene indicato come [GOF94] acronimo di "The Gang of Four".
    http://www.amazon.com/exec/obidos/ISBN=0201633612
  4. FastObject (conosciuto un tempo come Poet) è un database ad oggetti per C++ e Java. Dalle buone performance, non fa rimpiangere i database relazionali.
    La ditta produttrice (POET) è europea, ed offre un buon supporto.
    http://www.fastobjects.com/eu/
  5. GemStone, uno dei più famosi database ad oggetti.
    http://www.gemstone.com
Discuti sul forum   Stampa

Cosa ne pensi di questo articolo?

Discussioni

Questo articolo o l'argomento ti ha interessato? Parliamone.