1. Che cos'è il Modello Proxy

Il modello proxy è un modello di design strutturale che funge da proxy per controllare l'accesso a un particolare oggetto. In base all'oggetto di destinazione (l'oggetto che viene proxy), il modello proxy fornisce un oggetto proxy tramite il quale i client possono accedere all'oggetto di destinazione, consentendo l'aggiunta di funzionalità aggiuntive all'oggetto di destinazione.

1.1 Definizione del Modello Proxy

Il modello proxy è un modello di design che coinvolge la collaborazione di due o più oggetti. Un oggetto è l'effettivo oggetto di destinazione chiamato, mentre uno o più altri oggetti agiscono come oggetti proxy. Gli oggetti proxy intercettano l'accesso all'oggetto di destinazione, fornendo un modo indiretto per accedere all'oggetto di destinazione.

1.2 Scopo e Obiettivi del Modello Proxy

Il principale scopo del modello proxy è fornire un modo indiretto per accedere all'oggetto di destinazione, consentendo l'aggiunta di funzionalità aggiuntive all'oggetto di destinazione. Gli oggetti proxy possono gestire logiche comuni, come il controllo dell'accesso all'oggetto di destinazione, la memorizzazione nella cache e la registrazione. Il modello proxy può anche implementare il caricamento ritardato, istanziando l'oggetto di destinazione solo quando necessario.

2. Caratteristiche e Vantaggi del Modello Proxy

Il modello proxy ha le seguenti caratteristiche e vantaggi:

  • Può estendere la funzionalità dell'oggetto di destinazione senza modificarlo.
  • Può controllare l'accesso all'oggetto di destinazione attraverso l'oggetto proxy.
  • Può eseguire operazioni aggiuntive prima o dopo l'accesso all'oggetto di destinazione.
  • Può implementare il caricamento ritardato, istanziando l'oggetto di destinazione solo quando necessario.

3. Esempi di Applicazioni Pratiche del Modello Proxy

Il modello proxy è ampiamente utilizzato in molti scenari applicativi. Ecco alcuni esempi comuni di applicazioni pratiche:

  • Proxy Remoto: Utilizzato per accedere agli oggetti in rete in modo locale.
  • Proxy Virtuale: Utilizzato per creare oggetti costosi solo quando necessario.
  • Proxy di Sicurezza: Utilizzato per controllare l'accesso agli oggetti.
  • Riferimento Intelligente: Utilizzato per eseguire operazioni aggiuntive durante l'accesso agli oggetti, come il conteggio degli oggetti.

4.1 Diagramma delle Classi UML

Di seguito è riportato il diagramma delle classi UML del Modello Proxy in Golang:

Modello Proxy in Golang

4.2 Introduzione all'Esempio

Supponiamo di avere un'interfaccia Subject che definisce un metodo Request. Abbiamo una classe di implementazione concreta RealSubject, che implementa l'interfaccia Subject. Quindi creiamo una classe proxy Proxy, che contiene un oggetto RealSubject e implementa anche l'interfaccia Subject. Nel metodo Request della classe Proxy, possiamo eseguire operazioni aggiuntive prima o dopo la chiamata al metodo Request di RealSubject.

4.3 Passaggio 1: Definizione dell'Interfaccia Proxy

In primo luogo, dobbiamo definire un'interfaccia Subject che contenga un metodo Request:

package main

type Subject interface {
    Request()
}

4.4 Passaggio 2: Implementazione dell'Oggetto di Destinazione

Successivamente, implementiamo l'oggetto di destinazione specifico RealSubject, che implementa l'interfaccia Subject:

package main

import "fmt"

type RealSubject struct {}

func (r *RealSubject) Request() {
    fmt.Println("RealSubject: Gestione della Richiesta")
}

4.5 Passaggio 3: Implementazione dell'Oggetto Proxy

Successivamente, creiamo un oggetto proxy, Proxy, che contiene un oggetto RealSubject e implementa l'interfaccia Subject. Nel metodo Request del Proxy, possiamo eseguire alcune operazioni aggiuntive prima o dopo la chiamata al metodo Request di RealSubject:

package main

import "fmt"

type Proxy struct {
    realSubject *RealSubject
}

func (p *Proxy) Request() {
    fmt.Println("Proxy: Pre-Request")
    
    if p.realSubject == nil {
        p.realSubject = &RealSubject{}
    }
    
    p.realSubject.Request()
    
    fmt.Println("Proxy: Post-Request")
}

4.6 Passaggio 4: Invocazione dell'Oggetto Proxy

Infine, possiamo utilizzare l'oggetto proxy, Proxy, per invocare i metodi dell'oggetto presidiato, RealSubject:

package main

func main() {
    proxy := Proxy{}
    proxy.Request()
}

L'esecuzione del codice sopra produrrà l'output:

Proxy: Pre-Request
RealSubject: Gestione della Richiesta
Proxy: Post-Request

5.1 Differenze e Connessione tra il Pattern Proxy e il Pattern Decorator

Sia il pattern proxy che il pattern decorator sono pattern di progettazione strutturali, entrambi dei quali contengono un oggetto target e un oggetto proxy/decorator. Tuttavia, ci sono alcune differenze tra i due:

  • Il pattern proxy coinvolge generalmente il controllo di accesso all'oggetto target, mentre il pattern decorator si concentra più sull'estensione dell'oggetto target.
  • Il pattern proxy esegue tipicamente operazioni aggiuntive prima o dopo l'oggetto target, mentre il pattern decorator aggiunge dinamicamente funzionalità extra sopra l'oggetto target.

5.2 Confronto tra Proxy Statico e Proxy Dinamico

Il pattern proxy può essere suddiviso in proxy statico e proxy dinamico. Il proxy statico determina il tipo dell'oggetto proxy a tempo di compilazione, e l'oggetto proxy è scritto manualmente dal programmatore. Il proxy dinamico, d'altro canto, genera dinamicamente l'oggetto proxy a tempo di esecuzione sulla base dell'interfaccia dell'oggetto target. Il proxy dinamico è più flessibile ma anche più complesso rispetto al suo controparte statico.

5.3 Applicazione del Pattern Proxy nelle Microservices

Il pattern proxy può essere applicato in un'architettura a microservizi. Ad esempio, possiamo utilizzare un proxy per incapsulare l'accesso ad altri microservizi ed implementare meccanismi come bilanciamento del carico, limitazione del tasso e chiusura dei circuiti a livello del proxy. Questo può migliorare l'affidabilità e le prestazioni del sistema. Il pattern proxy può anche essere utilizzato per implementare la funzionalità di scoperta dei servizi e di routing.