Ohjelmointi

Ota hallinta välityspalvelimen suunnittelukuvion avulla

Ystäväni - ei vähempää lääkäri - kertoi kerran vakuuttaneensa ystävänsä suorittamaan hänelle yliopistokokeen. Joku, joka ottaa jonkun toisen paikan, tunnetaan nimellä valtakirja. Ystäväni valitettavasti hänen välityspalvelin joi hieman liian paljon edellisenä iltana ja epäonnistui testissä.

Ohjelmistossa välityspalvelimen suunnittelumalli osoittautuu hyödylliseksi monissa yhteyksissä. Esimerkiksi Java XML Pack -pakettia käytettäessä välityspalvelimia käytetään verkkopalveluihin JAX-RPC: n (Java-sovellusliittymä XML-pohjaisiin etäkäyttökutsuihin) avulla. Esimerkki 1 osoittaa, kuinka asiakas käyttää yksinkertaista Hello World -verkkopalvelua:

Esimerkki 1. SOAP (Simple Object Access Protocol) -välityspalvelin

public class HelloClient {public static void main (String [] args) {kokeile {HelloIF_Stub valtakirja = (HelloIF_Stub) (uusi HelloWorldImpl (). GetHelloIF ()); valtakirja._setTargetEndpoint (argumentit [0]); System.out.println (valtakirja.sanoHello ("Duke!")); } catch (Exception ex) {ex.printStackTrace (); }}} 

Esimerkin 1 koodi muistuttaa läheisesti Hello World -verkkopalveluesimerkkiä, joka sisältyy JAX-RPC: hen. Asiakas saa viitteen välityspalvelimeen ja asettaa välityspalvelimen päätepisteen (verkkopalvelun URL-osoitteen) komentoriviargumentilla. Kun asiakkaalla on viite välityspalvelimeen, se kutsuu välityspalvelimen sano Hei() menetelmä. Välityspalvelin välittää kyseisen menetelmän kutsun verkkopalvelulle, joka usein sijaitsee eri koneella kuin asiakkaan kone.

Esimerkki 1 havainnollistaa välityspalvelimen suunnittelumallin yhtä käyttöä: etäobjektien käyttöä. Valtuutukset osoittautuvat hyödyllisiksi myös kalliiden resurssien luomisessa kysynnän mukaan, virtuaalinen välityspalvelin, ja objektien käytön valvomiseksi, a suojauksen välityspalvelin.

Jos olet lukenut "Koristele Java-koodisi" (JavaWorld, Joulukuussa 2001), saatat nähdä yhtäläisyyksiä sisustajan ja välityspalvelimen suunnittelumallien välillä. Molemmat mallit käyttävät välityspalvelinta, joka välittää menetelmäpuhelut toiselle objektille, joka tunnetaan nimellä todellinen aihe. Ero on siinä, että välityspalvelimen mallilla välityspalvelimen ja todellisen kohteen välinen suhde asetetaan tyypillisesti kääntöaikaan, kun taas sisustajat voidaan rakentaa rekursiivisesti ajon aikana. Mutta olen edessäni itsestäni.

Tässä artikkelissa esitän ensin välityspalvelinkuvion, aloittaen välityspalveluesimerkistä Swing-kuvakkeille. Lopuksi tarkastelen JDK: n sisäänrakennettua tukea Proxy-mallille.

merkintä: Tämän sarakkeen kahdessa ensimmäisessä erässä - "Hämmästytä kehittäjäystäviäsi suunnittelumalleilla" (lokakuu 2001) ja "Koristele Java-koodisi" - keskustelin Decorator-kuviosta, joka liittyy läheisesti välityspalvelimen kuvioon, joten voit halutessasi tarkastella näitä artikkeleita ennen jatkamista.

Välityspalvelimen malli

Välityspalvelin: Hallitse pääsyä objektiin välityspalvelimella (tunnetaan myös nimellä korvike tai paikkamerkki).

Swing-kuvakkeet ovat alla olevassa "Välityspalvelimen sovellettavuus" -osassa käsitellyistä syistä erinomainen valinta välityspalvelimen kuvion havainnollistamiseksi. Aloitan lyhyellä esittelyllä Swing-kuvakkeista, jota seuraa keskustelu Swing-kuvakepalvelimesta.

Swing-kuvakkeet

Swing-kuvakkeet ovat pieniä kuvia, joita käytetään painikkeissa, valikoissa ja työkaluriveissä. Voit myös käyttää Swing-kuvakkeita itsestään, kuten Kuva 1 kuvaa.

Kuvassa 1 esitetty sovellus on lueteltu esimerkissä 2:

Esimerkki 2. Swing-kuvakkeet

tuo java.awt. *; tuo java.awt.event. *; tuo javax.swing. *; // Tämä luokka testaa kuvakuvaketta. julkinen luokka IconTest laajentaa JFrame-kehystä {private static String IMAGE_NAME = "mandrill.jpg"; yksityinen staattinen int FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 268, FRAME_HEIGHT = 286; yksityinen kuvake imageIcon = null, imageIconProxy = null; staattinen julkinen void main (String args []) {IconTest app = new IconTest (); app.show (); } public IconTest () {super ("Icon Test"); imageIcon = uusi ImageIcon(IMAGE_NAME); setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } public void maali (grafiikka g) {super.paint (g); Sisäosan lisäykset = getInsets (); imageIcon.paintIcon(tämä, g, insets.left, insets.top); }} 

Edellinen sovellus luo kuvan kuvakkeen - esimerkin javax.swing.ImageIcon - ja ohittaa sitten maali() tapa maalata kuvake.

Swing image-icon välityspalvelimet

Kuvassa 1 esitetty sovellus on heikko Swing-kuvakuvien käyttö, koska sinun tulisi käyttää kuvakuvakkeita vain pieniin kuviin. Tämä rajoitus on olemassa, koska kuvien luominen on kallista, ja ImageIcon esiintymät luovat kuvansa, kun ne rakennetaan. Jos sovellus luo useita isoja kuvia kerralla, se voi aiheuttaa merkittävän suorituskyvyn. Lisäksi, jos sovellus ei käytä kaikkia kuviaan, on tuhlaavaa luoda ne etukäteen.

Parempi ratkaisu lataa kuvat tarpeen mukaan. Tätä varten välityspalvelin voi luoda oikean kuvakkeen ensimmäisen kerran paintIcon () menetelmää kutsutaan. Kuvassa 2 on sovellus, joka sisältää kuvakuvakkeen (vasemmalla) ja kuvan-kuvakepalvelimen (oikealla). Yläkuvassa näkyy sovellus heti sen käynnistämisen jälkeen. Koska kuvakuvakkeet lataavat kuvia rakennettaessa, kuvakkeen kuva näkyy heti, kun sovelluksen ikkuna avautuu. Sitä vastoin välityspalvelin lataa kuvan vasta, kun se on maalattu ensimmäistä kertaa. Kunnes kuva latautuu, välityspalvelin piirtää kehän ympärille reunan ja näyttää "Ladataan kuvaa ...". Kuvan 2 alalaidassa näkyy sovellus sen jälkeen, kun välityspalvelin on ladannut kuvan.

Olen listannut esimerkissä 3 kuvassa 2 esitetyn sovelluksen:

Esimerkki 3. Swing-kuvakepalvelimet

tuo java.awt. *; tuo java.awt.event. *; tuo javax.swing. *; // Tämä luokka testaa virtuaalisen välityspalvelimen, joka on välityspalvelin, joka // viivästyttää kalliiden resurssien (kuvakkeiden) lataamista, kunnes kyseistä // resurssia tarvitaan. public class VirtualProxyTest laajentaa JFrame-kehystä {private static String IMAGE_NAME = "mandrill.jpg"; yksityinen staattinen int IMAGE_WIDTH = 256, IMAGE_HEIGHT = 256, SPACING = 5, FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 530, FRAME_HEIGHT = 286; yksityinen kuvake imageIcon = null, imageIconProxy = null; staattinen julkinen void main (String args []) {VirtualProxyTest app = new VirtualProxyTest (); app.show (); } public VirtualProxyTest () {super ("Virtuaalinen välityspalvelintesti"); // Luo kuvakuvake ja kuva-kuvake-välityspalvelin. imageIcon = uusi ImageIcon (IMAGE_NAME); imageIconProxy = uusi ImageIconProxy(IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT); // Aseta kehyksen rajat ja kehyksen oletusarvoinen // sulkutoiminto. setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } public void paint (grafiikka g) {super.paint (g); Sisäosan lisäykset = getInsets (); imageIcon.paintIcon(tämä, g, insets.left, insets.top); imageIconProxy.paintIcon(tämä, g, insets.left + IMAGE_WIDTH + SPACING, // leveys ins.top); // korkeus}} 

Esimerkki 3 on melkein identtinen esimerkin 2 kanssa lukuun ottamatta kuva-kuvake-välityspalvelimen lisäämistä. Esimerkki 3 -sovellus luo kuvakkeen ja välityspalvelimen konstruktoriinsa ja ohittaa sen maali() menetelmä maalata ne. Ennen kuin keskustelet välityspalvelimen toteutuksesta, katso kuva 3, joka on luokkakaavio välityspalvelimen todellisesta aiheesta, javax.swing.ImageIcon luokassa.

javax.swing.Icon käyttöliittymä, joka määrittää Swing-kuvakkeiden olemuksen, sisältää kolme tapaa: paintIcon (), getIconWidth ()ja getIconHeight (). ImageIcon luokka toteuttaa Kuvake käyttöliittymä ja lisää omat menetelmänsä. Kuvakuvakkeet ylläpitävät myös kuvien kuvausta ja viittausta niihin.

Image-icon-välityspalvelimet toteuttavat Kuvake käyttöliittymä ja ylläpitää viittausta kuvakuvakkeeseen - todelliseen kohteeseen - kuten kuvion 4 luokkakaavio havainnollistaa.

ImageIconProxy luokka on lueteltu esimerkissä 4.

Esimerkki 4. ImageIconProxy.java

// ImageIconProxy on kuvakkeen välityspalvelin (tai korvike). // Välityspalvelin viivästyttää kuvan lataamista, kunnes // kuva piirretään ensimmäisen kerran. Kun kuvake lataa kuvaa, // välityspalvelin piirtää reunan ja viesti "Ladataan kuvaa ..." -luokka ImageIconProxy toteuttaa javax.swing.Icon {private Kuvake realIcon = nolla; looginen onIconCreated = väärä; yksityinen merkkijono imageName; yksityisen int leveys, korkeus; public ImageIconProxy (String imageName, int leveys, int korkeus) {this.imageName = imageName; this.width = leveys; tämä.korkeus = korkeus; } public int getIconHeight () {return isIconCreated? korkeus: realIcon.getIconHeight (); } public int getIconWidth () {return isIconCreated realIcon == null? leveys: realIcon.getIconWidth (); } // Välityspalvelimen paint () -menetelmä on ylikuormitettu piirtämään reunus // ja viesti ("Ladataan kuvaa ..."), kun kuva // latautuu. Kun kuva on ladattu, se piirretään. Huomaa //, että välityspalvelin ei lataa kuvaa ennen kuin sitä // todella tarvitaan. public void paintIcon (lopullinen komponentti c, grafiikka g, int x, int y) { jos (isIconCreated) { realIcon.paintIcon(c, g, x, y); } muu { g.piirrä oikea(x, y, leveys-1, korkeus-1); g.drawString("Ladataan kuvaa ...", x + 20, y + 20); // Kuvake luodaan (eli kuva ladataan) // toiselle säikeelle. synkronoitu (tämä) {SwingUtilities.invokeLater (uusi Runnable () {public void run () {yritä {// Hidasta kuvan latausprosessia. Thread.currentThread (). sleep (2000); // ImageIcon-konstruktori luo kuvan . todellinen kuvake = uusi ImageIcon (imageName); onIconCreated = tosi; } catch (InterruptedException ex) {ex.printStackTrace (); } // Maalaa kuvakkeen osa uudelleen, kun // -kuvake on luotu. c. maalaa (); } }); } } } } 

ImageIconProxy ylläpitää viittausta todelliseen kuvakkeeseen todellinen kuvake jäsenmuuttuja. Kun välityspalvelin maalataan ensimmäisen kerran, todellinen kuvake luodaan erilliseen säikeeseen, jotta suorakulmio ja merkkijono voidaan maalata (puhelut g.drawRect () ja g.drawString () eivät tule voimaan ennen paintIcon () menetelmä palauttaa). Kun todellinen kuvake on luotu ja siksi kuva on ladattu, kuvakkeen näyttävä komponentti maalataan uudelleen. Kuvassa 5 on esitetty näiden tapahtumien sekvenssikaavio.

Kuvan 5 sekvenssikaavio on tyypillinen kaikille valtakirjoille: Valtakirjat hallitsevat pääsyä todelliseen kohteeseen. Tämän valvonnan takia valtakirjat välittävät usein todellisen aiheensa, kuten esimerkissä 4 luetellun kuvakuvapalvelimen tapauksessa. Tämä ilmentyminen on yksi eroja välityspalvelimen kuvion ja sisustajan kuvion välillä: Koristelijat luovat harvoin todellisia aiheitaan.

JDK: n sisäänrakennettu tuki välityspalvelimen suunnittelumallille

Proxy-malli on yksi tärkeimmistä suunnittelumalleista, koska se tarjoaa vaihtoehdon toiminnallisuuden laajentamiselle perinnöllä. Tämä vaihtoehto on esineiden koostumus, missä objekti (välityspalvelin) välittää edelleen -menetelmän kutsut suljetulle objektille (todellinen aihe).

Objektikoostumus on parempi kuin perintö, koska koostumuksella suljetut esineet voivat manipuloida suljettua esinettään vain suljetun kohteen rajapinnan kautta, mikä johtaa löysään kytkentään esineiden välillä. Sitä vastoin perinnöllä luokat ovat tiukasti kytketty perusluokkaansa, koska perusluokan sisäosat ovat näkyvä sen laajennuksiin. Tämän näkyvyyden takia perintöä kutsutaan usein nimellä valkoisen laatikon uudelleenkäyttö. Toisaalta, sommittelun kanssa, ympäröivän kohteen sisäosat ovat ei näkyvä suljettuun esineeseen (ja päinvastoin); siksi koostumukseen viitataan usein nimellä mustan laatikon uudelleenkäyttö. Kun kaikki asiat ovat tasa-arvoisia, mustan laatikon uudelleenkäyttö (koostumus) on parempi kuin valkoisen laatikon uudelleenkäyttö (perintö), koska löysä kytkentä johtaa muokattavampiin ja joustavampiin järjestelmiin.

Koska välityspalvelinkuvio on niin tärkeä, J2SE 1.3 (Java 2 Platform, Standard Edition) ja sen ulkopuolella tukee sitä suoraan. Tähän tukeen kuuluu kolme luokkaa java.lang.reflect paketti: Välityspalvelin, Menetelmäja KutsuKäsittelijä. Esimerkki 5 esittää yksinkertaisen esimerkin, joka käyttää JDK-tukea välityspalvelimelle: