- A Classic Example: Image Proxies
- Image Proxies Reconsidered
- Remote Proxies
- Dynamic Proxies
- Summary
Image Proxies Reconsidered
At this point, you might ask whether design patterns have helped you. You faithfully implemented a pattern, and now you’re looking at tearing it out. In fact, this is natural and healthy, although it happens more often in real development than in books. An author—with the help of reviewers—can rethink and replace an inferior design before any reader sees it. In practice, a design pattern can help you get an application running and can facilitate the discussion of your design. In the _ImageIconProxy example at Oozinoz, the pattern has served its purpose, even though it is much simpler to achieve the effect you desire without a literal implementation of a proxy.
The ImageIcon class operates on an Image object. Rather than forwarding painting requests to a separate ImageIcon object, it is easier to operate on the Image object that ImageIcon wraps. Figure 11.4 shows an LoadingImageIcon class—from com.oozinoz.imaging—that has only two methods beyond its constructor: load() and run().
Figure 11.4 The LoadingImageIcon class works by switching the Image object that it holds.
The load() method in this revised class still receives a JFrame object to call back after the desired image is loaded. When load() executes, it calls _setImage() with the image held by LOADING, repaints the frame, and starts a separate thread for itself. The run() method, executing in a separate thread, creates a new ImageIcon object for the file named in the constructor, calls setImage() with the image held by this object, and repacks the frame.
The almost-complete code for LoadingImageIcon.java is:
package com.oozinoz.imaging; import javax.swing.ImageIcon; import javax.swing.JFrame;
public class LoadingImageIcon 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")); protected String filename; protected JFrame callbackFrame; public LoadingImageIcon(String filename) { super(ABSENT.getImage()); this.filename = filename; } public void load(JFrame callbackFrame) { // Challenge! } public void run() { // Challenge! } }
Challenge 11.3
Fill in the code for load() and run() in LoadingImageIcon.
A solution appears on page 377.
The revised code is less coupled to the design of ImageIcon, relying primarily on getImage() and setImage() rather than on the mechanics of which methods to forward. In fact, no forwarding exists: LoadingImageIcon is a proxy in spirit but not in structure.
The Proxy pattern’s reliance on forwarding can create a maintenance burden. For example, should the underlying object change, the Oozinoz team will have to update the proxy. To avoid this burden, you should usually consider alternatives to Proxy, but there will be times when Proxy is the right choice. In particular, when the object for which you need to intercept messages is executing on another machine, there may be no substitute for Proxy.