Strukturalny wzorzec projektowy Proxy, jego zadaniem jest zbudowanie klasy, która zastępuje/emuluje zachowanie innego klasy/obiektu Jest to jeden z najprostszych wzorców projektowych, bardzo często niepozornie siedzący w kodzie.

Zastosowanie takiej kombinacji gdzie jeden obiekt zastępuje inny obiekt jest:

  • Kontrola dostępu do ochranianego obiektu – np. dostęp do danych po autoryzacji użytkownika
  • Opóźnienie tworzenia kosztownego obiektu, obiekt jest tworzony kiedy to jest niezbędne – tworzenie na żądanie
  • Emulacja zdalnego obiektu, np.: dane obiektu przesyłane są przez internet
  • Cachowanie pewnych danych obiektu – niektóre dane klasy długo się generują, albo są przeliczane wcześniej
  • Dodatkowe operacje wykonywane przy dostępie do obiektu np.: zliczanie ilości referencji, czy tzw. Sprytne wskaźniki

Proxy jest w założeniu bardzo prostym wzorcem, ale umożliwia realizowanie dodatkowych zadań, które nie były przewidziane w interfejsie emulowanego obiektu.

Przykładowa implementacja, klasa dostarcza wygenerowane obrazy, przy pierwszym wywołaniu dostarczone są tylko grafiki poglądowe – generowanie właściwych wymaga bardzo dużo mocy obliczeniowej.

package pl.shad.net.blog;

/**
 * Interfejs dostępu do danych
 */
interface ImageInterface{
    String getImage();
}

/**
 * Główna klasa generująca dane
 */
class Image implements ImageInterface{

    @Override
    public String getImage(){
        return "HiRes image data ...";
    }
}

/**
 * Klasa proxy, przy pierwszym wywołaniu
 * daje dane poglądowe
 */
class ProxyImage implements ImageInterface{

    private Image image;
    private int counter = 0;

    @Override
    public String getImage(){

        counter++;
        if (counter > 1){
            if (image == null){
                image = new Image();
            }
            return image.getImage();
        }
        return "LoRes proxy thumbnail ...";
    }
}

/**
 * Testowa klasa uruchomieniowa
 */
public class DesignPatternsProxy{

    public static void main(String[] args){

        //
        // Odwołania do głównego obiektu bez użycia proxy
        //
        ImageInterface image = new Image();
        System.out.println("Object without proxy:");
        System.out.println("First access: " + image.getImage());
        System.out.println("Second access: " + image.getImage());

        //
        // Odwołania do głównego obiektu z użyciem obiektu proxy
        //
        image = new ProxyImage();
        System.out.println("Object with proxy:");
        System.out.println("First access: " + image.getImage());
        System.out.println("Second access: " + image.getImage());
    }
}