710 likes | 884 Views
Unit 6 Proxy. Summary prepared by Kirk Scott. Design Patterns in Java Chapter 11 Proxy. Summary prepared by Kirk Scott. The Introduction Before the Introduction. The chapter on the Proxy design pattern in the book is not ideal It is broken into four different parts
E N D
Unit 6Proxy Summary prepared by Kirk Scott
Design Patterns in JavaChapter 11Proxy Summary prepared by Kirk Scott
The Introduction Before the Introduction • The chapter on the Proxy design pattern in the book is not ideal • It is broken into four different parts • 1. An illustration of the design pattern for image loading • After explaining the example, the book states that although it illustrates the pattern, the resulting design is not desirable
2. The book then refactors the bad design into something it considers better. • It refers to this design as being a proxy in spirit but not in structure • As a consequence, it’s not clear whether the second example should stick in your mind as an illustration of the concepts involved or whether the first example is better because it is structurally closer
3. The book then considers the use of what it calls remote proxies • Proxies can definitely be useful in this environment • However, writing code that is distributed on different hardware platforms is beyond the scope of this course • Therefore, this section of the chapter will only be covered in passing
4. The last section of the chapter concerns dynamic proxies • This is also a useful application area for the design pattern • However, it is not necessarily a frequently occurring application • Like the previous section, this will only be covered in passing
Beginning of Book Material • Customary apportionment of responsibility in a design means that every class is responsible for implementing the code necessary to support its public interface (interface in the generic, non-Java sense) • As with the other responsibility patterns, the Proxy design pattern is used in cases where the customary treatment of responsibility isn’t appropriate or can be improved upon
The book outlines three examples where this might be the case: • 1. When the base object might take too long to load • 2. When the base object is on another computer • 3. When you would like to intercept method calls to a base object so that you can wrap the underlying call to that object with code of your own
In those cases a software design might include a proxy class • A proxy object stands in for a base object • Calls are made to the proxy • The proxy then forwards those calls to the base object
Book definition: • The intent of the Proxy pattern is to control access to an object by providing a surrogate, or placeholder, for it.
A Classic Example: Image Proxies • A proxy is a substitute or stand-in for a base object • As such, it is desirable for it to have an interface that is nearly identical to the interface of the base object • The proxy works by receiving the calls and “judiciously” or selectively forwarding the requests to the underlying object
A classic use of proxies is to avoid the waiting time associated with loading images in applications • Suppose the application contains graphical elements which hold the images • A proxy for a graphical element could take the step of displaying a small, temporary image, while the real image is being loaded in the background
In other words, a load() call is issued to the proxy • The proxy loads a temporary image and calls load() on the base object in the background • The real load() may be set to run in a separate thread • The user sees the temporary image quickly and can proceed using the application • The loading time of the real image doesn’t affect response time
The book admits up front that the following shortcomings may apply to a proxy design: • The resulting design may be brittle or fragile • By this the authors mean that maintenance and modification may be difficult • This is a bad sign for the application of a design pattern
The difficulty arises directly from the fact that the proxy is supposed to duplicate the interface of the underlying object • If that interface includes lots of methods, you have two choices, which you’ve seen before • Implement them all: This requires lots of work • Implement only some of them: This means that the proxy can only handle a subset of calls that the base object can handle
The next overhead illustrates the idea of a graphical placeholder • Initially an application would present the “Absent” icon • After pressing the “Load” button, the “Loading…” icon would be displayed as a stand-in • In the background, the loading of the real image would be started
From the standpoint of mechanics, the book proposes displaying .jpeg images as icons that are inserted into labels • This is the basic syntax: • ImageIcon icon = new ImageIcon(“images/fest.jpg”); • JLabel label = new JLabel(icon);
The idea now is to give the JLabel a proxy instead of the real icon • Then • The application makes use of the label • The label calls the proxy • And the proxy calls the base image/icon object • The following sequence diagram illustrates the idea
Aside from problems that the book admits to with the example, there is another complication • In the previous descriptions, reference was made to “loading an image in the background” • The question is, what does this mean?
In this example it will mean having the proxy implement the Runnable interface so that the proxy can load the image in a separate thread • If you’ve had CS 320 before or have encountered threads in some other setting, this might be meaningful • If not, don’t worry • Although central to this example, it is not central to the structure and intent of the design pattern
The overall plan of action for the proxy example is this: • There is a Java class, ImageIcon, which is the graphical item which is displayed in a JLabel • The proxy, ImageIconProxy is a subclass of the ImageIcon class
The ImageIconProxy class has three instance variables for images • A static ImageIcon variable for the Absent icon • A static ImageIcon variable for the Loading icon • And a non-static ImageIcon variable for whichever ImageIcon is currently displayed
The ImageIconProxy class has an instance variable to hold the String path name of the real image to load • The ImageIconProxy class also has an instance variable that holds a reference to the frame of the application that is using it
The ImageIconProxy class overrides a few of the many methods in the ImageIcon class • In particular it has a load() method that triggers the loading of an image • Because it implements Runnable, it also has a run() method • See the UML diagram on the following overhead
When an instance of the ImageIconProxy class is constructed, it takes in the String path name of an actual image to be loaded • The load() method takes in a reference to a frame as a parameter • When called, the load() method switches the current image to “Loading” • It then repaints the frame • After that, it starts a new thread for loading the actual image
The run() method basically just does the loading of the actual image • The code for the ImageIconProxy follows • There are a few blanks in the code for the challenge that comes afterwards
import java.awt.*; • import javax.swing.*; • public class ImageIconProxy extends ImageIcon implements Runnable • { • static final ImageIcon ABSENT = new ImageIcon(ClassLoader.getSystemResource("images/absent.jpg")); • static final ImageIcon LOADING = new ImageIcon(ClassLoader.getSystemResource("images/loading.jpg")); • ImageIcon current = ABSENT; • protected String filename; • protected JFramecallbackFrame;
public ImageIconProxy(String filename) • { • super(ABSENT.getImage()); • this.filename = filename; • } • public void load(JFramecallbackFrame) • { • this.callbackFrame = callbackFrame; • current = LOADING; • callbackFrame.repaint(); • new Thread(this).start(); • } • public void run() • { • current = new ImageIcon(ClassLoader.getSystemResource(filename)); • callbackFrame.pack(); • }
public intgetIconHeight() • { • // Challenge! • } • public intgetIconWidth() • { • // Challenge! • } • public synchronized void paintIcon(Component c, Graphics g, int x, int y) • { • // Challenge! • } • }
Challenge 11.1 • An ImageIconProxy object accepts three image display calls that it must pass on to the current image. Write the code for getIconHeight(), getIconWidth(), and paintIcon() for the ImageIconProxy class.
Solution 11.1 • One solutions is: • [See next overhead.]
public intgetIconHeight() • { • return current.getIconHeight(); • } • public intgetIconWidth() • { • return current.getIconWidth(); • } • public synchronized void paintIcon(Component c, Graphics g, int x, int y) • { • current.paintIcon(c, g, x, y); • } • }
Before moving on with the book’s discussion, I would simply like to illustrate exactly how their example of a proxy works structurally • The ImageIconProxy class has an instance variable which is a reference to an ImageIcon, the current image • The situation can be diagrammed as shown on the following overhead
Recall that the ImageIconProxy class is a subclass of the ImageIcon class • It also implements the Runnable interface • Combining the previous diagram with the diagram that the book gave of the inheritance and interface relationships gives the diagram on the following overhead • I don’t claim that this is a generic picture of the structure of a proxy • It is, however, a more complete picture of what the book has done to create this proxy class
Challenge 11.2 • The ImageIconProxy class is not a well-designed, reusable component. Point out two problems with the design.
Solution 11.2 • Problems with the design include the following: • 1. Forwarding only a subset of calls to an underlying ImageIcon object is dangerous. • The ImageIconProxy class inherits a dozen fields and at least 25 methods from the ImageIcon class.
To be a true proxy, the ImageIconProxy object needs to forward most or all of these calls. • Thorough forwarding would require many potentially erroneous methods, and this code would require maintenance as the ImageIcon class and its superclasses change over time. • [Note that when the authors say erroneous, what the apparently mean is that trying to completely duplicate the interface would be error prone.]
2. You might question whether the “Absent” image and the desired image are in the right places in the design. • It might make more sense to have the images passed in rather than making the class responsible for finding them. • [This seems like a relatively minor criticism. In their second, improved design the authors don’t really change this.]
In summary, the software design presented so far does include the Proxy design pattern • However, the design that results from using this pattern is apparently NOT so good • Whenever you apply a pattern, it’s not sufficient to justify its use on the grounds that it’s a pattern
Its use has to lead to a better design • That said, even though this design may be poor, it may also be the clearest illustration of the use of the Proxy design pattern that is presented in this chapter
Image Proxies Reconsidered • Preliminary comment mode on: • What the authors do next is quite simple • I’m not sure their explanation really makes it clear what’s happening because it’s so simple • To give a preview, what they do is stop trying to make a proxy • Instead, they solve their design problem with a subclass with no pretenses to being a proxy
The key point is this: • With a proxy, you are either committed to reproducing the whole interface • Or you decide to do a subset • With the subclass solution you rely on all of the inherited methods of the superclass • Plus you add a few selected methods needed for the application
The book now replaces the ImageIconProxy class with a LoadingImageIcon class which is a subclass of ImageIcon • The LoadingImageIcon class has two methods in it, load() and run() • The ImageIconProxy class had a few more methods in it, in particular paintIcon()
The key idea is that fundamentally the ImageIcon class contains an instance of the Image class • The ImageIcon class contains all the methods needed for manipulating the image • It is much cleaner to simply let the LoadingImageIcon class inherit and use these methods rather than trying to duplicate them • A UML diagram of the new solution is given on the following overhead