Dziś poznasz jeden z prostszych wzorców projektowych (strukturalnych). Wzorzec ten nosi nazwę proxy, co jest czasami tłumaczone jako pełnomocnik (takie tłumaczenie można znaleźć między innymi w kultowej już pozycji autorstwa „bandy czworga” – Ericha Gamma, Richarda Helema, Ralpha Johnsona oraz Johna Vlissidesa – Wzorce projektowe, wydanej przez WNT)
Wzorzec ten ma na celu zbudowanie klasy będącej odpowiednikiem innej klasy, pozwalając jednocześnie na zarządzanie dostępem do niej:
- gdy chcesz wykonywać pewne zdalne obiekty(remote proxy – pełnomocnik zdalny),
- gdy z pewnych względów nie chcesz tworzyć obiektu danej klasy aż do chwili wywołania jednej z jego metod, np. gdy z góry wiesz, że utworzenie takiego obiektu jest bardzo czasochłonne bądź zasobochłonne (virtual proxy – pełnomocnik wirtualny),
- gdy chcesz kontrolować dostęp do pewnego obiektu twojego systemu (protection proxy – pełnomocnik ochraniający),
- gdy poza akcją wykonywaną przez obiekt danej klasy musisz wykonać także dodatkowe akcje powiązane z jego metodą bądź metodami (smart proxy – sprytny pełnomocnik).
Nie są to wszystkie możliwe użycia wzorca proxy, lecz te najbardziej typowe. Nic jednak nie stoi na przeszkodzie, aby wykorzystać go w innym celu.
Jak działa proxy? Zawsze w sposób analogiczny. Obudujmy więc, korzystając z tego wzorca, przykładową klasę Klient. Klasa ta implementuje interfejs Uzytkownik:
interface Uzytkownik {
public function getImie();
public function setImie($strImie);
public function getNazwisko();
public function setNazwisko($strNazwisko);
public function zapisz();
public function usun();
}
public interface Uzytkownik {
public String getImie();
public void setImie(String imie);
public String getNazwisko();
public void setNazwisko(String nazwisko);
public void zapisz();
public void usun();
}
Nasza klasa Klient jest równie prosta (jak
zwykle ciała funkcji nie robią nic pożytecznego
– przykłady te mają jedynie zaprezentować
w możliwie łatwy i przejrzysty sposób samą ideę
działania wzorca):
class Klient implements Uzytkownik {
private $strImie;
private $strNazwisko;
public function getImie() {
return $this->strImie;
}
public function setImie($strImie) {
$this->strImie = $strImie;
}
public function getNazwisko() {
return $this->strNazwisko;
}
public function setNazwisko($strNazwisko) {
$this->strNazwisko = $strNazwisko;
}
public function zapisz() {
//zapisywanie danych użytkownika
}
public function usun() {
//usuwanie użytkownika
}
}
public class Klient implements Uzytkownik
{
private String imie;
private String nazwisko;
public String getImie() {
return imie;
}
public void setImie(String imie) {
this.imie = imie;
}
public String getNazwisko() {
return nazwisko;
}
public void setNazwisko(String nazwisko) {
this.nazwisko = nazwisko;
}
public void zapisz() {
//zapisywanie danych użytkownika
}
public void usun() {
//usuwanie użytkownika
}
}
Nasza klasa Proxy także dziedziczy po interfejsie
Użytkwonik, udając tym samym klasę, którą
obudowuje:
class Proxy implements Uzytkownik {
private $objKlient;
public function __construct() {
$this->objKlient = new Klient();
//inne działania proxy w dane metodzie
}
public function getImie() {
return $this->objKlient->getImie();
//inne działania proxy w dane metodzie
}
public function setImie($strImie) {
$this->objKlient->setImie($strImie);
//inne działania proxy w dane metodzie
}
public function getNazwisko() {
return $this->objKlient->getNazwisko();
//inne działania proxy w dane metodzie
}
public function setNazwisko($strNazwisko) {
$this->objKlient->setNazwisko($strNazwisko);
//inne działania proxy w dane metodzie
}
public function zapisz() {
$this->objKlient->zapisz();
//inne działania proxy w dane metodzie
}
public function usun() {
$this->objKlient->usun();
//inne działania proxy w dane metodzie
}
}
public class Proxy implements Uzytkownik {
private Klient klient;
public Proxy() {
klient = new Klient();
}
public String getImie() {
return klient.getImie();
//inne działania proxy w dane metodzie
}
public void setImie(String imie) {
klient.setImie(imie);
//inne działania proxy w dane metodzie
}
public String getNazwisko() {
return klient.getNazwisko();
//inne działania proxy w dane metodzie
}
public void setNazwisko(String nazwisko) {
klient.setNazwisko(nazwisko);
//inne działania proxy w dane metodzie
}
public void zapisz() {
klient.zapisz();
//inne działania proxy w dane metodzie
}
public void usun() {
klient.usun();
//inne działania proxy w dane metodzie
}
}
Użycie wzorca proxy sprowadza się do użycia
naszej nowej klasy Proxy w miejscu klasy Klient.
Jako że obie mają ten sam interfejs, nie sprawia to
żadnego problemu:
$objUzytkownik = new Proxy();
$objUzytkownik->setImie(\'Jan\');
$objUzytkownik->setNazwisko(\'Kowalski\');
$objUzytkownik->zapisz();
public class Test {
public static void main(String[] args)
{
Uzytkownik uzytkownik = new Proxy();
uzytkownik.setImie(\"Jan\");
uzytkownik.setNazwisko(\"Kowalski\");
uzytkownik.zapisz();
}
}
Podsumowanie
Wzorzec ten jest prawdopodobnie najprostszym
z poznanych przez ciebie do tej pory.
Możliwe, że już od dawna z niego korzystasz, nie
wiedząc nawet, że jest to jeden ze wzorców i jaką
nosi nazwę. Jeśli tak, warto jego nazwę zapamiętać.
Pozwoli to na wygodną komunikację z innymi
programistami, operującymi terminologią wzorców
projektowych.