Προγραμματισμός

Πάρτε τον έλεγχο με το μοτίβο του Proxy

Ένας φίλος μου - ένας γιατρός, τουλάχιστον - μου είπε κάποτε ότι έπεισε έναν φίλο να κάνει εξετάσεις για το κολέγιο. Κάποιος που παίρνει τη θέση κάποιου άλλου είναι γνωστός ως πληρεξούσιο. Δυστυχώς για τον φίλο μου, ο πληρεξούσιος του ήπιε πάρα πολύ το προηγούμενο βράδυ και απέτυχε στο τεστ.

Στο λογισμικό, το σχέδιο μεσολάβησης αποδεικνύεται χρήσιμο σε πολλά περιβάλλοντα. Για παράδειγμα, χρησιμοποιώντας το Πακέτο Java XML, χρησιμοποιείτε διακομιστές μεσολάβησης για πρόσβαση σε υπηρεσίες Web με JAX-RPC (Java API για κλήσεις απομακρυσμένης διαδικασίας που βασίζονται σε XML). Το παράδειγμα 1 δείχνει πώς ένας πελάτης αποκτά πρόσβαση σε μια απλή υπηρεσία Hello World Web:

Παράδειγμα 1. Ένας διακομιστής μεσολάβησης SOAP (Simple Object Access Protocol)

δημόσια τάξη HelloClient {public static void main (String [] args) {δοκιμάστε {HelloIF_Stub πληρεξούσιο = (HelloIF_Stub) (νέο HelloWorldImpl (). GetHelloIF ()); πληρεξούσιο._setTargetEndpoint (args [0]); System.out.println (πληρεξούσιο.sayHello ("Duke!")); } catch (Exception ex) {ex.printStackTrace (); }}} 

Ο κώδικας του παραδείγματος 1 μοιάζει πολύ με το παράδειγμα υπηρεσιών Hello World Web που περιλαμβάνεται στο JAX-RPC. Ο πελάτης λαμβάνει μια αναφορά στο διακομιστή μεσολάβησης και ορίζει το τελικό σημείο του διακομιστή μεσολάβησης (το URL της υπηρεσίας Web) με ένα όρισμα γραμμής εντολών. Μόλις ο πελάτης έχει μια αναφορά στον πληρεξούσιο, καλεί τους διακομιστές μεσολάβησης πες γεια() μέθοδος. Ο διακομιστής μεσολάβησης προωθεί αυτή τη μέθοδο κλήσης στην υπηρεσία Web, η οποία συχνά βρίσκεται σε διαφορετικό μηχάνημα από αυτόν του πελάτη.

Το παράδειγμα 1 απεικονίζει μία χρήση για το σχέδιο σχεδίασης διακομιστή μεσολάβησης: πρόσβαση σε απομακρυσμένα αντικείμενα. Οι διακομιστές μεσολάβησης αποδεικνύονται επίσης χρήσιμοι για τη δημιουργία δαπανηρών πόρων κατόπιν ζήτησης, α εικονικός διακομιστής μεσολάβησης, και για τον έλεγχο της πρόσβασης σε αντικείμενα, α πληρεξούσιο προστασίας.

Εάν έχετε διαβάσει το "Διακοσμήστε τον κώδικα Java" (JavaWorld, Δεκέμβριος 2001), μπορεί να δείτε ομοιότητες μεταξύ των προτύπων του Decorator και του Proxy. Και τα δύο μοτίβα χρησιμοποιούν έναν διακομιστή μεσολάβησης που προωθεί τη μέθοδο κλήσεων σε άλλο αντικείμενο, γνωστό ως πραγματικό θέμα. Η διαφορά είναι ότι, με το μοτίβο διακομιστή μεσολάβησης, η σχέση μεταξύ ενός διακομιστή μεσολάβησης και του πραγματικού θέματος ορίζεται συνήθως στο χρόνο μεταγλώττισης, ενώ οι διακοσμητές μπορούν να κατασκευαστούν αναδρομικά κατά το χρόνο εκτέλεσης. Αλλά προχωράω μπροστά μου.

Σε αυτό το άρθρο, παρουσιάζω πρώτα το μοτίβο διακομιστή μεσολάβησης, ξεκινώντας με ένα παράδειγμα διακομιστή μεσολάβησης για εικονίδια Swing. Καταλήγω με μια ματιά στην ενσωματωμένη υποστήριξη του JDK για το μοτίβο Proxy.

Σημείωση: Στις δύο πρώτες δόσεις αυτής της στήλης - "Καταπλήξτε τους φίλους σας προγραμματιστή με μοτίβα σχεδίασης" (Οκτώβριος 2001) και "Διακοσμήστε τον κώδικα Java" - Συζήτησα το μοτίβο Διακοσμητή, το οποίο σχετίζεται στενά με το μοτίβο διακομιστή μεσολάβησης, οπότε μπορεί να θέλετε για να δείτε αυτά τα άρθρα πριν προχωρήσετε.

Το μοτίβο διακομιστή μεσολάβησης

Διακομιστής μεσολάβησης: Ελέγξτε την πρόσβαση σε ένα αντικείμενο με έναν διακομιστή μεσολάβησης (επίσης γνωστό ως υποκατάστατο ή placeholder).

Τα εικονίδια Swing, για λόγους που συζητούνται στην ενότητα "Εφαρμογή διακομιστή μεσολάβησης" παρακάτω, αποτελούν μια εξαιρετική επιλογή για την απεικόνιση του μοτίβου διακομιστή μεσολάβησης. Ξεκινώ με μια σύντομη εισαγωγή στα εικονίδια Swing, ακολουθούμενη από μια συζήτηση για έναν διακομιστή μεσολάβησης εικονιδίων Swing.

Εικονίδια Swing

Τα εικονίδια Swing είναι μικρές εικόνες που χρησιμοποιούνται σε κουμπιά, μενού και γραμμές εργαλείων. Μπορείτε επίσης να χρησιμοποιήσετε τα εικονίδια Swing μόνοι τους, όπως απεικονίζει το Σχήμα 1.

Η εφαρμογή που φαίνεται στο Σχήμα 1 παρατίθεται στο Παράδειγμα 2:

Παράδειγμα 2. Εικονίδια Swing

εισαγωγή java.awt. *; εισαγωγή java.awt.event. *; εισαγωγή javax.swing. *; // Αυτή η τάξη δοκιμάζει ένα εικονίδιο εικόνας. Η δημόσια τάξη IconTest επεκτείνει το JFrame {private static String IMAGE_NAME = "mandrill.jpg"; ιδιωτικό στατικό int FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 268, FRAME_HEIGHT = 286; ιδιωτικό εικονίδιο imageIcon = null, imageIconProxy = null; static public void main (String args []) {IconTest app = new IconTest (); app.show (); } δημόσιο IconTest () {super ("Icon Test"); imageIcon = νέο ImageIcon(IMAGE_NAME); setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } δημόσια κενή βαφή (Γραφικά g) {super.paint (g); Insets insets = getInsets (); imageIcon.paintIcon(αυτό, g, insets.left, insets.top); }} 

Η προηγούμενη εφαρμογή δημιουργεί ένα εικονίδιο εικόνας - μια παρουσία του javax.swing.ImageIcon - και στη συνέχεια παρακάμπτει το χρώμα() μέθοδος για να βάψετε το εικονίδιο.

Εναλλαγή διακομιστών μεσολάβησης εικόνας-εικονιδίου

Η εφαρμογή που φαίνεται στο Σχήμα 1 είναι κακή χρήση εικονιδίων εικόνας Swing επειδή πρέπει να χρησιμοποιείτε εικονίδια εικόνας μόνο για μικρές εικόνες. Αυτός ο περιορισμός υπάρχει επειδή η δημιουργία εικόνων είναι ακριβή και Εικονίδιο οι περιπτώσεις δημιουργούν τις εικόνες τους όταν κατασκευάζονται. Εάν μια εφαρμογή δημιουργεί πολλές μεγάλες εικόνες ταυτόχρονα, θα μπορούσε να προκαλέσει σημαντική επιτυχία στην απόδοση. Επίσης, εάν η εφαρμογή δεν χρησιμοποιεί όλες τις εικόνες της, είναι άχρηστη η δημιουργία τους εκ των προτέρων.

Μια καλύτερη λύση φορτώνει εικόνες καθώς γίνονται απαραίτητες. Για να το κάνει αυτό, ένας διακομιστής μεσολάβησης μπορεί να δημιουργήσει το πραγματικό εικονίδιο την πρώτη φορά που οι διακομιστές μεσολάβησης εικονίδιο χρωμάτων () καλείται μέθοδος. Το σχήμα 2 δείχνει μια εφαρμογή που περιέχει ένα εικονίδιο εικόνας (στα αριστερά) και έναν διακομιστή μεσολάβησης εικονιδίου εικόνας (στα δεξιά). Η κορυφαία εικόνα δείχνει την εφαρμογή αμέσως μετά την κυκλοφορία της. Επειδή τα εικονίδια εικόνας φορτώνουν τις εικόνες τους όταν κατασκευάζονται, η εικόνα ενός εικονιδίου εμφανίζεται μόλις ανοίξει το παράθυρο της εφαρμογής. Αντίθετα, ο διακομιστής μεσολάβησης δεν φορτώνει την εικόνα του έως ότου χρωματιστεί για πρώτη φορά. Μέχρι να φορτωθεί η εικόνα, ο πληρεξούσιος σχεδιάζει ένα περίγραμμα γύρω από την περίμετρο του και εμφανίζει την ένδειξη "Φόρτωση εικόνας ..." Η κάτω εικόνα στο Σχήμα 2 δείχνει την εφαρμογή αφού ο διακομιστής μεσολάβησης φορτώσει την εικόνα του.

Έχω αναφέρει την εφαρμογή που φαίνεται στο Σχήμα 2 στο Παράδειγμα 3:

Παράδειγμα 3. διακομιστές μεσολάβησης εικονιδίων Swing

εισαγωγή java.awt. *; εισαγωγή java.awt.event. *; εισαγωγή javax.swing. *; // Αυτή η τάξη δοκιμάζει έναν εικονικό διακομιστή μεσολάβησης, ο οποίος είναι ένας διακομιστής μεσολάβησης που // καθυστερεί τη φόρτωση ενός ακριβού πόρου (ένα εικονίδιο) έως ότου αυτός ο // πόρος είναι απαραίτητος. δημόσια κλάση VirtualProxyTest επεκτείνει το JFrame {private static String IMAGE_NAME = "mandrill.jpg"; ιδιωτικό στατικό int IMAGE_WIDTH = 256, IMAGE_HEIGHT = 256, SPACING = 5, FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 530, FRAME_HEIGHT = 286; ιδιωτικό εικονίδιο imageIcon = null, imageIconProxy = null; static public void main (String args []) {VirtualProxyTest app = νέο VirtualProxyTest (); app.show (); } δημόσιο VirtualProxyTest () {super ("Virtual Proxy Test"); // Δημιουργήστε ένα εικονίδιο εικόνας και έναν διακομιστή μεσολάβησης εικονιδίου εικόνας. εικόνα = νέο ImageIcon (IMAGE_NAME); imageIconProxy = νέο ImageIconProxy(IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT); // Ορίστε τα όρια του πλαισίου και την προεπιλεγμένη // κλείσιμο λειτουργίας του πλαισίου. setBounds (FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } δημόσιο κενό χρώμα (Γραφικά g) {super.paint (g); Insets insets = getInsets (); imageIcon.paintIcon(αυτό, g, insets.left, insets.top); imageIconProxy.paintIcon(αυτό, g, insets.left + IMAGE_WIDTH + SPACING, // width insets.top); // ύψος } } 

Το Παράδειγμα 3 είναι σχεδόν πανομοιότυπο με το Παράδειγμα 2, εκτός από την προσθήκη του διακομιστή μεσολάβησης εικονιδίου εικόνας. Η εφαρμογή Παράδειγμα 3 δημιουργεί το εικονίδιο και τον διακομιστή μεσολάβησης στον κατασκευαστή της και παρακάμπτει το χρώμα() μέθοδος για να τα βάψετε. Πριν συζητήσετε την εφαρμογή του πληρεξούσιου, δείτε το Σχήμα 3, το οποίο είναι ένα διάγραμμα τάξης του πραγματικού θέματος του πληρεξούσιου, το javax.swing.ImageIcon τάξη.

ο javax.swing.Icon διεπαφή, η οποία καθορίζει την ουσία των εικονιδίων Swing, περιλαμβάνει τρεις μεθόδους: εικονίδιο χρωμάτων (), getIconWidth (), και getIconHeight (). ο Εικονίδιο τάξη εφαρμόζει το Εικόνισμα διεπαφή και προσθέτει τις δικές της μεθόδους. Τα εικονίδια εικόνων διατηρούν επίσης μια περιγραφή και μια αναφορά στις εικόνες τους.

Οι διακομιστές μεσολάβησης εικόνας-εικονιδίου εφαρμόζουν το Εικόνισμα διεπαφή και διατηρήστε μια αναφορά σε ένα εικονίδιο εικόνας - το πραγματικό θέμα - όπως απεικονίζει το διάγραμμα τάξης στο Σχήμα 4.

ο ImageIconProxy Η τάξη παρατίθεται στο Παράδειγμα 4.

Παράδειγμα 4. ImageIconProxy.java

// ImageIconProxy είναι ένας διακομιστής μεσολάβησης (ή υποκατάστατης) για ένα εικονίδιο. // Ο διακομιστής μεσολάβησης καθυστερεί τη φόρτωση της εικόνας έως την πρώτη φορά που σχεδιάζεται η εικόνα //. Ενώ το εικονίδιο φορτώνει την εικόνα του, ο διακομιστής μεσολάβησης // σχεδιάζει ένα περίγραμμα και το μήνυμα "Φόρτωση εικόνας ..." Η κλάση ImageIconProxy υλοποιεί το javax.swing.Icon {private Εικονίδιο realIcon = μηδέν; boolean isIconCreated = ψευδές; ιδιωτική συμβολοσειρά imageName; ιδιωτικό int πλάτος, ύψος δημόσιο ImageIconProxy (συμβολοσειρά imageName, int πλάτος, int ύψος) {this.imageName = imageName; this.width = πλάτος; this.height = ύψος; } δημόσιο int getIconHeight () {return isIconCreated; ύψος: realIcon.getIconHeight (); } δημόσια int getIconWidth () {return isIconCreated realIcon == null; πλάτος: realIcon.getIconWidth (); } // Η μέθοδος paint () του διακομιστή μεσολάβησης είναι υπερφορτωμένη για να σχεδιάσετε ένα περίγραμμα // και ένα μήνυμα ("Φόρτωση εικόνας ...") ενώ η εικόνα // φορτώνεται. Αφού φορτωθεί η εικόνα, σχεδιάζεται. Παρατηρήστε // ότι ο διακομιστής μεσολάβησης δεν φορτώνει την εικόνα έως ότου // πραγματικά απαιτείται. public void paintIcon (τελικό στοιχείο c, γραφικά g, int x, int y) { εάν (isIconCreated) { realIcon.paintIcon(c, g, x, y); } αλλιώς { g.drawRect(x, y, πλάτος-1, ύψος-1); g.drawString("Φόρτωση εικόνας ...", x + 20, y + 20); // Το εικονίδιο δημιουργείται (σημαίνει ότι η εικόνα έχει φορτωθεί) // σε άλλο νήμα. συγχρονισμένη (αυτό) {SwingUtilities.invokeLater (new Runnable () {public void run () {try {// Επιβράδυνση της διαδικασίας φόρτωσης εικόνας. Thread.currentThread (). sleep (2000); // Ο κατασκευαστής ImageIcon δημιουργεί τη . πραγματικό εικονίδιο = νέο ImageIcon (imageName); isIconCreated = αλήθεια; } catch (InterruptException ex) {ex.printStackTrace (); } // Ζωγραφίστε ξανά το στοιχείο του εικονιδίου μετά τη δημιουργία του εικονιδίου //. γ. επαναβαφή (); } }); } } } } 

ImageIconProxy διατηρεί μια αναφορά στο πραγματικό εικονίδιο με το πραγματικό εικονίδιο μεταβλητή μέλους. Την πρώτη φορά που χρωματίζεται ο διακομιστής μεσολάβησης, το πραγματικό εικονίδιο δημιουργείται σε ξεχωριστό νήμα για να επιτρέπεται η βαφή του ορθογωνίου και της συμβολοσειράς (οι κλήσεις προς g.drawRect () και g.drawString () μην τεθεί σε ισχύ μέχρι το εικονίδιο χρωμάτων () επιστρέφει μέθοδο). Μετά τη δημιουργία του πραγματικού εικονιδίου και, επομένως, η εικόνα φορτώνεται, το στοιχείο που εμφανίζει το εικονίδιο ξαναβάφεται. Το σχήμα 5 δείχνει ένα διάγραμμα ακολουθίας για αυτά τα συμβάντα.

Το διάγραμμα ακολουθίας του Σχήματος 5 είναι χαρακτηριστικό όλων των διακομιστών μεσολάβησης: Οι διακομιστές μεσολάβησης ελέγχουν την πρόσβαση στο πραγματικό τους θέμα. Λόγω αυτού του ελέγχου, Οι πληρεξούσιοι συχνά αποδεικνύουν το πραγματικό τους θέμα, όπως συμβαίνει με τον διακομιστή μεσολάβησης εικονιδίου εικόνας που αναφέρεται στο Παράδειγμα 4. Αυτή η παρουσίαση είναι μία από τις διαφορές μεταξύ του μοτίβου διακομιστή μεσολάβησης και του μοτίβου Διακοσμητή: Οι διακοσμητές σπάνια δημιουργούν τα πραγματικά τους θέματα.

Η ενσωματωμένη υποστήριξη του JDK για το σχέδιο μεσολάβησης Proxy

Το μοτίβο διακομιστή μεσολάβησης είναι ένα από τα πιο σημαντικά μοτίβα σχεδίασης επειδή παρέχει μια εναλλακτική λύση στην επέκταση της λειτουργικότητας με κληρονομικότητα. Αυτή η εναλλακτική είναι σύνθεση αντικειμένου, όπου μια μέθοδο προώθησης αντικειμένου (διακομιστής μεσολάβησης) καλεί ένα κλειστό αντικείμενο (πραγματικό θέμα).

Η σύνθεση αντικειμένου είναι προτιμότερη από την κληρονομικότητα επειδή, με τη σύνθεση, το να περικλείει αντικείμενα μπορεί να χειριστεί μόνο το κλειστό αντικείμενο μέσω της διεπαφής του κλειστού αντικειμένου, με αποτέλεσμα χαλαρή σύζευξη μεταξύ αντικειμένων. Αντίθετα, με την κληρονομιά, οι τάξεις συνδέονται στενά με την βασική τους τάξη επειδή τα εσωτερικά μιας βασικής τάξης είναι ορατός στις επεκτάσεις του. Λόγω αυτής της ορατότητας, η κληρονομιά αναφέρεται συχνά ως επαναχρησιμοποίηση λευκού κουτιού. Από την άλλη πλευρά, με σύνθεση, τα εσωτερικά του αντικειμένου περιβλήματος είναι μη ορατό στο εσωκλειόμενο αντικείμενο (και αντίστροφα). Ως εκ τούτου, η σύνθεση αναφέρεται συχνά ως επαναχρησιμοποίηση μαύρου κουτιού. Όλα τα πράγματα είναι ίδια, η επαναχρησιμοποίηση μαύρου κουτιού (σύνθεση) είναι προτιμότερη από την επαναχρησιμοποίηση λευκού κουτιού (κληρονομικότητα) επειδή η χαλαρή σύζευξη οδηγεί σε πιο ευέλικτα και ευέλικτα συστήματα.

Επειδή το μοτίβο μεσολάβησης είναι τόσο σημαντικό, το J2SE 1.3 (Java 2 Platform, Standard Edition) και πέρα ​​από αυτό το υποστηρίζει άμεσα. Αυτή η υποστήριξη περιλαμβάνει τρεις κατηγορίες από το java.lang.reflect πακέτο: Πληρεξούσιο, Μέθοδος, και Επίκληση χειριστή. Το παράδειγμα 5 δείχνει ένα απλό παράδειγμα που χρησιμοποιεί την υποστήριξη JDK για το μοτίβο διακομιστή μεσολάβησης:

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