Preuzmite kontrolu s uzorkom dizajna Proxy

Moj prijatelj - liječnik, ni manje ni više - jednom mi je rekao da je uvjerio prijatelja da položi ispit za fakultet. Netko tko zauzme mjesto nekoga drugog poznat je kao opunomoćenik. Na nesreću mog prijatelja, njegov je proxy noć popio malo previše i nije pao na testu.

U softveru se obrazac proxy dizajna pokazuje korisnim u brojnim kontekstima. Na primjer, koristeći Java XML Pack, koristite proxyje za pristup web uslugama s JAX-RPC (Java API za pozive udaljenih procedura temeljenih na XML-u). Primjer 1 pokazuje kako klijent pristupa jednostavnoj web usluzi Hello World:

Primjer 1. SOAP (Simple Object Access Protocol) proxy

javna klasa HelloClient {public static void main (String [] args) {try {HelloIF_Stub proxy = (HelloIF_Stub) (new HelloWorldImpl (). getHelloIF ()); proxy ._setTargetEndpoint (argumenti [0]); System.out.println ( proxy .sayHello ("Duke!")); } catch (Iznimka ex) {ex.printStackTrace (); }}}

Kôd primjera 1 vrlo sliči primjeru Hello World Web usluga uključenom u JAX-RPC. Klijent dobiva referencu na proxy i postavlja krajnju točku proxyja (URL web usluge) argumentom naredbenog retka. Jednom kada klijent uputi na proxy, on poziva sayHello()metodu proxyja . Proxy prosljeđuje poziv te metode web usluzi koja se često nalazi na računalu koji nije od klijenta.

Primjer 1 ilustrira jednu upotrebu uzorka dizajna proxyja: pristup udaljenim objektima. Proxyji se također pokazuju korisnima za stvaranje skupih resursa na zahtjev, virtualnog proxyja i za kontrolu pristupa objektima, zaštitnog proxyja.

Ako ste pročitali moj " Ukrasi svoj Java kôd" ( JavaWorld, prosinac 2001.), možda ćete primijetiti sličnosti između uzoraka dizajnera Decorator i Proxy. Oba uzorka koriste proxy koji prosljeđuje pozive metode na drugi objekt, poznat kao pravi subjekt. Razlika je u tome što se s uzorkom proxyja odnos između proxyja i stvarnog subjekta obično postavlja u vrijeme sastavljanja, dok se dekorateri mogu rekurzivno konstruirati tijekom izvođenja. Ali idem ispred sebe.

U ovom članku prvo uvodim uzorak proxyja, počevši od primjera proxyja za ikone Swing. Zaključujem osvrtom na ugrađenu podršku za proxy obrazac JDK.

Napomena: U prva dva dijela ovog stupca - "Zadivite svoje prijatelje programere uzorcima dizajna" (listopad 2001.) i "Ukrasite svoj Java kôd" - raspravljao sam o uzorku Decorator, koji je usko povezan s uzorkom proxyja, pa ste možda će htjeti pogledati ove članke prije nego što nastavite.

Proxy obrazac

Proxy: Kontrolirajte pristup objektu s proxyjem (poznat i kao surogat ili rezervirano mjesto).

Ikone ljuljačke, iz razloga koji su razmotreni u odjeljku "Primjenjivost proxyja" u nastavku, izvrstan su izbor za ilustraciju uzorka proxyja. Počinjem s kratkim uvodom u ikone Swing, nakon čega slijedi rasprava o proxyju Swing ikone.

Ikone ljuljačke

Ikone ljuljačke male su slike koje se koriste u gumbima, izbornicima i alatnim trakama. Ikone Swinga možete koristiti i same, kao što prikazuje slika 1.

Primjena prikazana na slici 1 navedena je u primjeru 2:

Primjer 2. Ikone ljuljačke

import java.awt. *; import java.awt.event. *; import javax.swing. *; // Ova klasa testira ikonu slike. javna klasa IconTest proširuje JFrame {private static String IMAGE_NAME = "mandrill.jpg"; privatni statički int FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 268, FRAME_HEIGHT = 286; privatna ikona imageIcon = null, imageIconProxy = null; static public void main (String args []) {Aplikacija IconTest = nova IconTest (); app.show (); } javni IconTest () {super ("Test testa"); imageIcon = nova ImageIcon (IMAGE_NAME); setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } javna boja za praznine (grafika g) {super.paint (g); Umetci umetci = getInsets (); imageIcon.paintIcon (this, g, insets.left, insets.top); }}

Prethodna aplikacija stvara ikonu slike - primjerak javax.swing.ImageIcon- i zatim nadjačava paint()metodu za bojanje ikone.

Swing proxyji slika-ikona

Program prikazan na slici 1 slabo koristi ikone Swing slike, jer biste ikone slika trebali koristiti samo za male slike. To ograničenje postoji jer je stvaranje slika skupo, a ImageIconprimjerci ih stvaraju kad su konstruirane. Ako aplikacija stvori više velikih slika odjednom, to bi moglo prouzročiti značajan pogodak u izvedbi. Također, ako aplikacija ne koristi sve svoje slike, rasipno je stvarati ih unaprijed.

Bolje rješenje učitava slike po potrebi. Da bi to učinio, proxy može stvoriti stvarnu ikonu kad se prvi put paintIcon()pozove metoda proxyja . Slika 2 prikazuje aplikaciju koja sadrži ikonu slike (s lijeve strane) i proxy slike-ikone (s desne strane). Gornja slika prikazuje aplikaciju odmah nakon pokretanja. Budući da ikone slika učitavaju svoje slike kad su izrađene, slika ikone prikazuje se čim se otvori prozor aplikacije. Suprotno tome, proxy ne učitava svoju sliku dok nije prvi put slikana. Dok se slika ne učita, proxy crta obrub oko njenog opsega i prikazuje "Učitavanje slike ..." Donja slika na slici 2 prikazuje aplikaciju nakon što je proxy učitao svoju sliku.

Naveo sam aplikaciju prikazanu na slici 2 u primjeru 3:

Primjer 3. Proxyji ikone Swing

import java.awt. *; import java.awt.event. *; import javax.swing. *; // Ova klasa testira virtualni proxy, koji je proxy koji // odgađa učitavanje skupog resursa (ikone) dok taj // resurs ne bude potreban. javna klasa VirtualProxyTest proširuje JFrame {private static String IMAGE_NAME = "mandrill.jpg"; privatni statički int IMAGE_WIDTH = 256, IMAGE_HEIGHT = 256, PROSTOR = 5, FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 530, FRAME_HEIGHT = 286; privatna ikona imageIcon = null, imageIconProxy = null; static public void main (String args []) {VirtualProxyTest app = novi VirtualProxyTest (); app.show (); } javni VirtualProxyTest () {super ("Test virtualnog proxyja"); // Stvaranje ikone slike i proxy slike-ikone. imageIcon = nova ImageIcon (IMAGE_NAME); imageIconProxy = novoImageIconProxy (IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT); // Postavi granice okvira i zadani okvir // zatvara operaciju. setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } javna boja za praznine (grafika g) {super.paint (g); Umetci umetci = getInsets (); imageIcon.paintIcon (this, g, insets.left, insets.top); imageIconProxy.paintIcon (this, g, insets.left + IMAGE_WIDTH + PROSTOR, // width insets.top); // visina}}

Primjer 3 gotovo je identičan primjeru 2, osim dodatka proxy-a image-icon. Aplikacija Primjer 3 stvara ikonu i proxy u svom konstruktoru i zamjenjuje svoju paint()metodu za njihovo slikanje. Prije rasprave o provedbi proxyja, pogledajte sliku 3, koja je dijagram klase stvarnog predmeta proxyja, javax.swing.ImageIconklase.

javax.swing.IconSučelje, koje definira bit Swing ikona, uključuje tri metode: paintIcon(), getIconWidth()i getIconHeight(). ImageIconKlasa implementira Iconsučelje, i dodaje metode za sebe. Ikone slika također sadrže opis i referencu na njihove slike.

Proxyji ikona slike implementiraju Iconsučelje i održavaju referencu na ikonu slike - stvarni subjekt - kao što ilustrira dijagram klase na slici 4.

ImageIconProxyKlasa je navedeno u Primjeru 4,

Primjer 4. ImageIconProxy.java

// ImageIconProxy je proxy (ili surogat) ikone. // Proxy odgađa učitavanje slike do prvog crtanja // slike. Dok ikona učitava svoju sliku, // proxy crta obrub i poruka "Učitavanje slike ..." klasa ImageIconProxy implementira javax.swing.Icon {private Icon realIcon = null; boolean isIconCreated= lažno; private String imageName; private int širina, visina; javni ImageIconProxy (Niz imageName, int širina, int visina) {this.imageName = imageName; this.width = širina; this.height = visina; } public int getIconHeight () {return isIconCreated? visina: realIcon.getIconHeight (); } public int getIconWidth () {return isIconCreated realIcon == null? širina: realIcon.getIconWidth (); } // Proxy-jeva metoda paint () preopterećena je za crtanje obruba // i poruke ("Učitavanje slike ...") dok se slika // učitava. Nakon učitavanja slike se crta. Primijetite // da proxy ne učitava sliku dok // zapravo nije potrebna. javna praznina paintIcon (konačna komponenta c, grafika g, int x, int y) { if (isIconCreated) { realIcon.paintIcon (c, g, x, y); } else { g.drawRect(x, y, širina-1, visina-1); g.drawString ("Učitavanje slike ...", x + 20, y + 20); // Ikona je stvorena (što znači da je slika učitana) // na drugoj niti. sinkronizirano (ovo) {SwingUtilities.invokeLater (new Runnable () {public void run () {try {// Usporite postupak učitavanja slike. Thread.currentThread (). sleep (2000); // Konstruktor ImageIcon stvara sliku . realIcon = new ImageIcon (imageName); isIconCreated = true;} catch (InterruptedException ex) {ex.printStackTrace ();} // Ponovo obojite komponentu ikone nakon što je stvorena ikona // c.repaint (); }} ); }}}}

ImageIconProxyodržava referencu na stvarnu ikonu s realIconvarijablom člana. Prvi put kad je proxy oslikan, prava ikona kreira se na zasebnoj niti kako bi se omogućilo bojanje pravokutnika i niza (pozivi g.drawRect()i g.drawString()ne stupaju na snagu dok se paintIcon()metoda ne vrati). Nakon stvaranja prave ikone, a time i učitavanja slike, komponenta koja prikazuje ikonu ponovno se boji. Slika 5 prikazuje dijagram redoslijeda za te događaje.

Dijagram redoslijeda na slici 5. tipičan je za sve proksije: Proksiji kontroliraju pristup stvarnom subjektu. Zbog te kontrole, proxyji često instanciraju svoj stvarni subjekt , kao što je slučaj s proxyjem ikone slike navedenim u Primjeru 4. Ta instancija jedna je od razlika između uzorka Proxy i uzorka Decorator: Dekoratori rijetko stvaraju svoje stvarne subjekte.

Ugrađena podrška JDK za obrazac dizajna Proxy

Uzorak proxyja jedan je od najvažnijih uzoraka dizajna jer pruža alternativu proširivanju funkcionalnosti nasljeđivanjem. Ta je alternativa kompozicija objekta, gdje objekt (proxy) prosljeđuje metodu zatvorenom objektu (stvarnom subjektu).

Sastav objekta je poželjniji od nasljeđivanja, jer kompozicijom zatvoreni objekti mogu kompozicijom upravljati svojim zatvorenim objektom samo putem sučelja zatvorenog objekta, što rezultira labavom spregom između objekata. Suprotno tome, s nasljeđivanjem, klase su usko povezane sa svojom osnovnom klasom jer su interni dijelovi osnovne klase vidljivi njenim proširenjima. Zbog te vidljivosti nasljeđivanje se često naziva ponovnom uporabom bijele kutije. S druge strane, sa sastavom, zatvoreni objekt nije vidljiv iznutra unutarnjeg predmeta (i obrnuto); stoga se sastav često naziva ponovnom upotrebom crne kutije. U svim jednakim uvjetima, ponovna upotreba crne kutije (sastav) poželjnija je od ponovne upotrebe bijele kutije (nasljeđivanje) jer labavo spajanje rezultira podatnijim i fleksibilnijim sustavima.

Budući da je obrazac proxyja toliko važan, J2SE 1.3 (Java 2 platforma, standardno izdanje) i šire ga izravno podržava. Ta podrška uključuje tri klase iz java.lang.reflectpaketa: Proxy, Methodi InvocationHandler. Primjer 5 prikazuje jednostavan primjer koji koristi JDK podršku za obrazac Proxy: