Tacsiazuma
Tacsiazuma A letscode.hu alapitója, több, mint egy évtized fejlesztői tapasztalattal. Neovim függő hobbi pilóta.

A Proxy Pattern szerepe az ókori rómában

A mai témánk egy igen egyszerű, ám hasznos tervezési minta lesz, mégpedig a proxy. A név sokaknak
ismerős lehet, akik próbáltak már céges netről betyárkodni és a dolog nem akart sehogy se összejönni nekik, mert egy bizonyos proxy lépett be a képbe. Na de mi is ez és mi célt szolgál? Cikkünkből megtudhatod!ploxy

Ha fellapozzuk a révai nagylexikont a proxy szervernél, akkor azt olvashatjuk, hogy ez beépül a webszerver és a kliens közé és a kliens nevében kéréseket eszközöl a webszerver felé, gyorsítótáraz, megváltoztatja a kliens kérését vagy éppen a webhely válaszát. Akkor most jöjjön az, ami számunkra fontos:

A proxy pattern a struktúrális minták közé tartozik, lényegében egy olyan osztály lesz, mely interfészében azonos a fogadó osztállyal, ezáltal nem megkülönböztethető, a kliens nem tudja, hogy ő “csak egy proxyhoz” kapcsolódott. A proxy a metódusaival forwardolja a kéréseket és visszaadja a fogadó osztály válaszát.

Most akkor csináljuk meg a fent említett webszerver/kliens/proxy triumvirátust a proxy pattern elemeit bemutatva!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Client { // ezek vagyunk mi

private $server;

public function __construct(ServerInterface $server) { // typehinteljük az interfészt

$this->server = $server; // sima konstruktor injectionnel adjuk át a szerver példányát

}

public function request($method, $url, $parameters) {

$this->server->incomingConnection($method, $url, $parameters); // nagyon leegyszerüsítve a dolog

}

}

Ebben eddig semmi érdekes nem volt, typehinteltünk a konstruktorban egy interfészt, így azon osztályok, amik implementálják azt az interfészt, hiba nélkül átadhatóak. Itt lesz a mi kis trükkünk, mivel mind a proxy, mind a webszerver osztályunk egyaránt implementálja majd az interfészt, ezáltal mindkettő használható lesz.

1
2
3
4
5
interface ServerInterface {

public function incomingConnection($method, $url, $parameters); // az interfészünk elég egyszerű lesz, egy metódust vittünk most bele

}

Nem is volt nehéz, ugye? Na de implementáljuk is ezt az interfészt a szerverünkben

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class WebServer implements ServerInterface { // a webszerver osztályunk

public function incomingConnection($method, $url, $parameters) {

// mindenféle feketemágia, aminek révén visszaadunk egy választ

return $response;

}

}

class ProxyServer implements ServerInterface { // a proxy osztályunk, ami szintén implementálja az adott interfészt

public function __construct() {

$this->server = new WebServer(); // héé, ez már ismerős... a proxy elrakja magának a szerver egy példányát, mivel azon keresztül fog működni

}

public function incomingConnection($method, $url, $parameters) { // ugye a kötelező metódus

return $this->server->incomingConnection($method, $url, $parameters); // szimplán forwardoljuk a dolgot

}

}

A fenti példában jól látni miről is szól a proxy patternünk. Meghívunk egy osztályt, ami önmagában foglalja azt az osztályt, amit mi el akarunk érni és a kéréseinket továbbítja neki.

Ezeket a kéréseket azonban meg lehet változtatni, valamint a válaszokat is, hiszen a proxy-n keresztülmegy a kérés.

Ha egyes osztályaink felé le akarjuk korlátozni a hozzáférést, akkor ilyen proxy-kon keresztül tudjuk elérni azt. Persze gyorsítótárazhatunk is, megvizsgálhatjuk ezt a kérést és még sok mást lehet beleszuszakolni ebbe a mintába, de most nézzünk pár példát mit lehet beletűzdelni:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ProxyServer implements ServerInterface { 

     public function __construct(WebServer $server, CacheInterface $cache) {
        // valamilyen cache-t is hozzáadunk és DI-zzük a szerverünket
        $this->server = $server 
        $this->cache = $cache;
     }

     public function incomingConnection($method, $url, $parameters) { 
         if (!$this->allowed) return $this->getErrorPage(403); // ha nem engedélyezett, akkor a saját 403-as oldalunkat adjuk vissza
         $key = md5($method, $url, $parameters); // valami egyedi azonosítót generálunk, ennek a módszerét rátok bízom
         if ($this->cache->has($key)) {
            return $this->cache->get($key); // visszaadjuk cache-ből
         } else {
            $this->cache->set($key, $this->server->incomingConnection($method, $url, $parameters); // lementjük cache-be
            return $this->cache->get($key); // aztán visszaadjuk onnan
         }
     }
}

Ezek csak szimpla metódusok, sokminden variálható, de ne feledjük, hogy ez csak egy helyettes osztály, így ne vegye át a másik osztályunk munkáját, csupán a szerepét.

comments powered by Disqus