Programovanie

Prevezmite kontrolu nad dizajnovým vzorom Proxy

Jeden môj priateľ - o nič menej lekár - mi raz povedal, že presvedčil priateľa, aby za neho urobil skúšku z vysokej školy. Niekto, kto nahradí niekoho iného, ​​sa nazýva a splnomocnenec. Nanešťastie pre môjho priateľa, jeho zástupca večer pred tým vypil až príliš veľa a test neprešiel.

V softvéri sa návrhový vzor Proxy osvedčil v mnohých kontextoch. Napríklad pomocou balíka Java XML Pack používate proxy na prístup k webovým službám pomocou JAX-RPC (Java API pre vzdialené volania procedúr založené na XML). Príklad 1 ukazuje, ako klient pristupuje k jednoduchej webovej službe Hello World:

Príklad 1. Server proxy SOAP (Simple Object Access Protocol)

public class HelloClient {public static void main (String [] args) {try {HelloIF_Stub splnomocnenec = (HelloIF_Stub) (nový HelloWorldImpl (). GetHelloIF ()); splnomocnenec._setTargetEndpoint (args [0]); System.out.println (splnomocnenec.sayHello („Vojvoda!“)); } catch (Výnimka ex) {ex.printStackTrace (); }}} 

Kód z príkladu 1 sa veľmi podobá príkladu webových služieb Hello World zahrnutému v JAX-RPC. Klient získa odkaz na server proxy a nastaví koncový bod servera proxy (adresa URL webovej služby) pomocou argumentu príkazového riadku. Keď má klient odkaz na proxy, vyvolá proxy povedz ahoj() metóda. Server proxy presmeruje túto metódu volania na webovú službu, ktorá sa často nachádza na inom počítači ako klient.

Príklad 1 ilustruje jedno použitie návrhového vzoru Proxy: prístup k vzdialeným objektom. Proxy servery sa tiež osvedčia pri vytváraní drahých zdrojov na požiadanie, a virtuálny proxy, a na riadenie prístupu k objektom, a ochrana proxy.

Ak ste si prečítali môj text „Ozdobte svoj kód Java“ (JavaWorld, December 2001), môžete vidieť podobnosti medzi návrhovými vzormi Decorator a Proxy. Oba vzory používajú proxy, ktoré presmeruje volania metód na iný objekt, známy ako skutočný predmet. Rozdiel je v tom, že so vzorom Proxy je vzťah medzi proxy a skutočným subjektom zvyčajne nastavený v čase kompilácie, zatiaľ čo dekorátory môžu byť rekurzívne zostavené za behu. Ale predbieham seba.

V tomto článku najskôr predstavím Proxy vzor, ​​počnúc príkladom proxy pre ikony Swing. Na záver sa pozriem na vstavanú podporu JDK pre vzor Proxy.

Poznámka: V prvých dvoch častiach tohto stĺpca - „Ohromte svojich vývojárskych priateľov dizajnovými vzormi“ (október 2001) a „Ozdobte svoj kód Java“ - som hovoril o vzorovom dekorátore, ktorý úzko súvisí so vzorom Proxy, takže si môžete želať predtým, ako budete pokračovať, si pozrite tieto články.

Vzor proxy

Proxy: Riadenie prístupu k objektu pomocou proxy (známe tiež ako náhradník alebo zástupný symbol).

Ikony hojdačky, z dôvodov popísaných v časti „Použiteľnosť proxy servera“ nižšie, predstavujú vynikajúcu voľbu na ilustráciu vzoru proxy servera. Začnem krátkym úvodom do ikon Swing, po ktorom nasleduje diskusia o proxy ikonách Swing.

Ikony hojdačky

Ikony hojdačky sú malé obrázky používané v tlačidlách, ponukách a paneloch nástrojov. Ikony Swing môžete použiť aj samotné, ako ukazuje obrázok 1.

Aplikácia zobrazená na obrázku 1 je uvedená v príklade 2:

Príklad 2. Ikony hojdania

import java.awt. *; import java.awt.event. *; importovať javax.swing. *; // Táto trieda testuje ikonu obrázka. verejná trieda IconTest rozširuje JFrame {private static String IMAGE_NAME = "mandrill.jpg"; private static int FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 268, FRAME_HEIGHT = 286; súkromná ikona imageIcon = null, imageIconProxy = null; static public void main (String args []) {IconTest app = new IconTest (); app.show (); } public IconTest () {super ("Test ikon"); imageIcon = nový ImageIcon(IMAGE_NAME); setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } public void paint (Grafika g) {super.paint (g); Vložky vložky = getInsets (); imageIcon.paintIcon(this, g, insets.left, insets.top); }} 

Predchádzajúca aplikácia vytvára ikonu obrázka - inštanciu javax.swing.ImageIcon - a potom potlačí farba () spôsob maľovania ikony.

Swing image-icon proxy

Aplikácia zobrazená na obrázku 1 zle využíva obrázkové ikony Swing, pretože obrázkové ikony by ste mali používať iba pre malé obrázky. Toto obmedzenie existuje, pretože vytváranie obrázkov je drahé a ImageIcon inštancie vytvárajú svoje obrázky, keď sú skonštruované. Ak aplikácia vytvorí veľa veľkých obrázkov naraz, mohlo by to spôsobiť výrazný zásah do výkonu. Ak aplikácia nepoužíva všetky svoje obrázky, je zbytočné ich vytvárať vopred.

Lepšie riešenie načíta obrázky podľa potreby. Za týmto účelom môže proxy server vytvoriť skutočnú ikonu prvýkrát paintIcon () metóda sa volá. Obrázok 2 zobrazuje aplikáciu, ktorá obsahuje obrazovú ikonu (vľavo) a proxy obrazovej ikony (vpravo). Horný obrázok zobrazuje aplikáciu tesne po jej spustení. Pretože obrázkové ikony načítavajú svoje obrázky, keď sú skonštruované, obrázok ikony sa zobrazí hneď po otvorení okna aplikácie. Naproti tomu server proxy nenačíta svoj obrázok, kým nie je vymaľovaný prvýkrát. Kým sa obrázok nenačíta, proxy nakreslí orámovanie po svojom obvode a zobrazí „Načítava sa obrázok ...“ Spodný obrázok na obrázku 2 zobrazuje aplikáciu po tom, ako proxy načíta svoj obrázok.

Uviedol som aplikáciu zobrazenú na obrázku 2 v príklade 3:

Príklad 3. Proxy zástupných ikon

import java.awt. *; import java.awt.event. *; importovať javax.swing. *; // Táto trieda testuje virtuálny proxy server, ktorý je proxy serverom, ktorý // odďaľuje načítanie drahého zdroja (ikony), kým tento zdroj // nebude potrebný. verejná trieda VirtualProxyTest rozširuje JFrame {private static String IMAGE_NAME = "mandrill.jpg"; private static int IMAGE_WIDTH = 256, IMAGE_HEIGHT = 256, SPACING = 5, FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 530, FRAME_HEIGHT = 286; súkromná ikona imageIcon = null, imageIconProxy = null; static public void main (String args []) {VirtualProxyTest app = new VirtualProxyTest (); app.show (); } public VirtualProxyTest () {super ("Test virtuálneho proxy servera"); // Vytvorte ikonu obrázka a proxy ikony obrázka. imageIcon = nový ImageIcon (IMAGE_NAME); imageIconProxy = nový ImageIconProxy(IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT); // Nastaví hranice rámca a predvolenú // operáciu rámca. setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } public void paint (Grafika g) {super.paint (g); Vložky vložky = getInsets (); imageIcon.paintIcon(this, g, insets.left, insets.top); imageIconProxy.paintIcon(this, g, insets.left + IMAGE_WIDTH + SPACING, // width insets.top); // výška}} 

Príklad 3 je takmer totožný s príkladom 2, s výnimkou pridania proxy servera s obrázkami. Aplikácia z príkladu 3 vytvorí vo svojom konštruktore ikonu a proxy server a prepíše ich farba () spôsob ich maľovania. Pred diskusiou o implementácii proxy sa pozrite na obrázok 3, ktorý je triednym diagramom skutočného predmetu proxy servera javax.swing.ImageIcon trieda.

The javax.swing.Icon rozhranie, ktoré definuje podstatu ikon Swing, obsahuje tri metódy: paintIcon (), getIconWidth ()a getIconHeight (). The ImageIcon trieda implementuje Ikona rozhranie a pridáva vlastné metódy. Ikony obrázkov tiež udržiavajú popis a odkaz na ich obrázky.

Proxy zástupcovia s obrázkami implementujú Ikona rozhranie a udržiavať odkaz na ikonu obrázka - skutočný predmet - ako ukazuje diagram tried na obrázku 4.

The ImageIconProxy trieda je uvedená v príklade 4.

Príklad 4. ImageIconProxy.java

// ImageIconProxy je proxy (alebo náhradný) ikony. // Proxy server oneskoruje načítanie obrázka, kým nie je prvýkrát nakreslený // obraz. Zatiaľ čo ikona načítava svoj obrázok, // proxy nakreslí orámovanie a správa „Načítava obrázok ...“ trieda ImageIconProxy implementuje javax.swing.Icon {private Ikona realIcon = null; boolean isIconCreated = nepravda; private String imageName; súkromná int šírka, výška; public ImageIconProxy (reťazec imageName, int šírka, int výška) {this.imageName = imageName; this.width = width; this.height = výška; } public int getIconHeight () {return isIconCreated? výška: realIcon.getIconHeight (); } public int getIconWidth () {return isIconCreated realIcon == null? width: realIcon.getIconWidth (); } // Metóda paint () proxy je preťažená, aby sa pri načítaní obrázku // nakreslilo ohraničenie // a správa („Načítava sa obrázok ...“). Po načítaní sa obrázok nakreslí. Všimnite si //, že proxy server nenačíta obrázok, kým ho // skutočne nebude treba. public void paintIcon (konečná zložka c, grafika g, int x, int y) { if (isIconCreated) { realIcon.paintIcon(c, g, x, y); } else { g.drawRect(x, y, šírka-1, výška-1); g.drawString(„Načítava sa obrázok ...“, x + 20, y + 20); // Ikona je vytvorená (tj. Je načítaný obrázok) // v inom vlákne. synchronized (this) {SwingUtilities.invokeLater (new Runnable () {public void run () {try {// Spomaliť proces načítania obrázkov. Thread.currentThread (). sleep (2000); // ImageIcon konštruktor vytvorí obrázok . realIcon = new ImageIcon (imageName); isIconCreated = pravda; } catch (InterruptedException ex) {ex.printStackTrace (); } // Po vytvorení ikony // premaľte komponent ikony. c.repaint (); } }); } } } } 

ImageIconProxy udržuje odkaz na skutočnú ikonu pomocou realIcon členská premenná. Pri prvom maľovaní proxy je skutočná ikona vytvorená v samostatnom vlákne, aby bolo možné namaľovať obdĺžnik a reťazec (volania g.drawRect () a g.drawString () nenadobudnú účinnosť, kým paintIcon () metóda sa vracia). Po vytvorení skutočnej ikony, a teda načítaní obrázka, sa komponent, ktorý zobrazuje ikonu, premaľuje. Obrázok 5 zobrazuje sekvenčný diagram pre tieto udalosti.

Poradový diagram na obrázku 5 je typický pre všetky servery proxy: Servery proxy riadia prístup k ich skutočným predmetom. Kvôli tejto kontrole proxy často inštancujú svoj skutočný predmet, ako je to v prípade proxy ikony obrázka uvedeného v príklade 4. Toto vytvorenie inštancie je jedným z rozdielov medzi vzorom Proxy a vzorom Decorator: Dekoranti zriedka vytvárajú svoje skutočné objekty.

Integrovaná podpora JDK pre návrhový vzor Proxy

Vzor Proxy je jedným z najdôležitejších vzorov návrhu, pretože poskytuje alternatívu k rozšíreniu funkčnosti o dedičnosť. Táto alternatíva je zloženie objektu, kde metóda (proxy) preposiela metódu volá na uzavretý objekt (skutočný subjekt).

Skladba objektu je vhodnejšia ako dedenie, pretože s kompozíciou môžu obklopujúce objekty manipulovať so svojím uzavretým objektom iba prostredníctvom rozhrania uzavretého objektu, čo vedie k voľnému spojeniu medzi objektmi. Naproti tomu s dedičstvom sú triedy pevne spojené so svojou základnou triedou, pretože interné prvky základnej triedy sú viditeľné k jeho rozšíreniam. Kvôli tejto viditeľnosti sa dedičstvo často označuje ako opätovné použitie bielej škatule. Na druhej strane, s kompozíciou sú vnútornosti ohraničujúceho objektu neviditeľný k uzavretému objektu (a naopak); preto sa zloženie často označuje ako opätovné použitie čiernej skrinky. Ak sú všetky veci rovnaké, opätovné použitie čiernej skrinky (zloženie) je vhodnejšie ako opätovné použitie bielej skrinky (dedičstvo), pretože voľné spojenie vedie k tvarovateľnejším a flexibilnejším systémom.

Pretože je Proxy vzor taký dôležitý, J2SE 1.3 (Java 2 Platform, Standard Edition) a ďalšie ho priamo podporuje. Táto podpora zahŕňa tri triedy z java.lang.reflect balenie: Proxy, Metódaa InvocationHandler. Príklad 5 ukazuje jednoduchý príklad, ktorý využíva podporu JDK pre vzor Proxy:

$config[zx-auto] not found$config[zx-overlay] not found