Chapter 15. The Proxy Pattern

The Proxy pattern is used to represent with a simpler object an object that is complex or time-consuming to create. If creating an object is expensive in time or computer resources, a Proxy allows you to postpone this creation until you need the actual object. A Proxy usually has the same methods as the full object that it represents. Once that full object is loaded, the Proxy passes on the method calls to the full object.

There are several cases where a Proxy can be useful:

  1. If an object, such as a large image, takes a long time to load

  2. If the object is on a remote machine and loading it over the network might be slow, especially during peak network load periods

  3. If the object has limited access rights. The proxy can then validate the access permissions for that user.

Proxies can also be used to distinguish between requesting an instance of an object and the actual need to access it. For example, program initialization might set up a number of objects, all of which might not be used right away. In that case, the Proxy can load the real object only when it is needed.

Consider a program that needs to load and display a large image. When the program starts, some indication that an image is to be displayed is needed so that the screen is set out correctly; however, the actual image display can be postponed until the image is completely loaded. This is particularly important in programs such as word processors and Web browsers that lay out text around the images before the images are available.

An image proxy can note the image and begin loading it in the background, while drawing a simple rectangle or other symbol to represent the image's extent on the screen before it appears. The proxy can even delay loading the image at all until it receives a paint request and only then begin the loading process.

Sample Code

In this example program, we create a simple program to display an image on a JPanel when it is loaded. Rather than loading the image directly, we use a class we call ImageProxy to defer loading and draw a rectangle around the image area until loading is completed.

public class ProxyDisplay extends JxFrame {
    public ProxyDisplay() {
        super("Display proxied image");
        JPanel p = new JPanel();
        getContentPane().add(p);
        p.setLayout(new BorderLayout());
        ImageProxy image = new ImageProxy("elliott.jpg", 321, 271);

        p.add("Center", image);
        p.add("North", new Label("      "));
        p.add("West", new Label("    "));
        setSize(370, 350);
        setVisible(true);
    }

Note that we create the instance of the Image Proxy just as we would have for an Image and that we add it to the enclosing JPanel as we would an actual image.

The ImageProxy class sets up the image loading and creates a MediaTracker object to follow the loading process within the constructor.

public class ImageProxy extends JPanel
implements Runnable {
    private int height, width;
    private MediaTracker tracker;
    private Image img;
    private JFrame frame;
    private Thread imageCheck;     //to monitor loading
//-----------------
    public ImageProxy(String filename, int w, int h) {
        height = h;
        width = w;

        tracker = new MediaTracker(this);
        img =
            Toolkit.getDefaultToolkit().
            getImage(filename);
    tracker.addImage(img, 0);       //watch for image loading

        imageCheck = new Thread(this);
        imageCheck.start();        //start 2nd thread monitor

        //this begins actual image loading
        try {
            tracker.waitForID(0,1);
        } catch (InterruptedException e) {
        }
    }

The waitForID method of the MediaTracker actually initiates loading. In this case, we put in a minimum wait time of 1 millisecond so that we can minimize apparent program delays.

The constructor also creates a separate thread imageCheck that checks the loading status every few milliseconds and then starts that thread running.

public void run() {
        /**this thread monitors image loading
        and repaints when done
        the 1000 millisecond is artificially long
        to allow the demo to display with a delay*/
        try {
            Thread.sleep(1000);
            while (! tracker.checkID(0))
                Thread.sleep(1000);
        } catch (Exception e) {
        }
        repaint ();
    }

For the purposes of this illustration program, we slowed the polling time down to 1 second so that we can see the program draw the rectangle and then refresh the final image.

Finally, the Proxy is derived from the JPanel component and therefore has a paint method. In this method, we draw a rectangle if the image is not loaded. If the image has been loaded, we erase the rectangle and draw the image.

public void paint(Graphics g) {
        if (tracker.checkID(0)) {
            height = img.getHeight(frame);//get height
            width = img.getWidth(frame);  //and width

            getsetColor(Color.lightGray); //erase box
            g.fillRect(0,0, width, height);
            g.drawImage(img, 0, 0, this); //draw image
        } else {
            //draw box outlining image if not loaded yet
            g.setColor(Color.black);
            g.drawRect(1, 1, width-2, height-2);
        }
    }

The program's two states are illustrated in Figure 15.1.

The proxy image display on the left is shown until the image on the right loads.

Figure 15.1. The proxy image display on the left is shown until the image on the right loads.

Copy-on-Write

You can also use Proxies to keep copies of large objects that may or may not change. If you create a second instance of an expensive object, a Proxy can decide that a copy is not needed yet, so it simply uses the original object. Then, if the program makes a change in the new copy, the Proxy can copy the original object and make the change in the new instance. This can save time and space when objects do not always change after they are instantiated.

Enterprise Java Beans

Enterprise Java Beans (EJB) are a set of classes and interfaces for writing well-encapsulated server code. They are not at all related to the Java Beans you use in client GUI programs. However, they do supply a convenient approach for accessing databases and other legacy data systems.

Each time you request a line of data from a database, you are making a new connection to an EJB. Clearly, there are a limited number of these connections available, so the remaining requests are cached within the Bean and a Proxy to the connection that eventually becomes the connection when one becomes available is returned.

Comparison with Related Patterns

Both the Adapter and the Proxy patterns constitute a thin layer around an object. However, the Adapter provides a different interface for an object, whereas the Proxy provides the same interface for the object but interposes itself where it can postpone processing or data transmission effort.

A Decorator also has the same interface as the object that it surrounds, but its purpose is to add additional (sometimes visual) function to the original object. A Proxy, by contrast, controls access to the contained class.

Thought Question

  1. You have designed a Java server that connects to a database. If several clients connect to your server at once, how could Proxies be of help?

Programs on the CD-ROM

Program Description

ProxyProxyDisplay.java

Displays a Proxy for the image for one second and then loads the image.

Summary of Structural Patterns

Following is a summary of the Structural patterns:

  • Adapter pattern. changes the interface of one class to that of another.

  • Bridge pattern. separates a class's interface from its implementation so that you can vary or replace the implementation without changing the client code.

  • Composite pattern. a collection of objects, any one of which may be aComposite or a leaf object.

  • Decorator pattern. a class that surrounds a given class, adds new capabilities to it, and passes all of the unchanged methods to the underlying class.

  • Façade pattern. groups a complex set of objects and provides a new, simpler interface to access those objects.

  • Flyweight pattern. provides a way to limit the proliferation of small, similar instances by moving some of the class data outside of the classand passing them in during various execution methods.

  • Proxy pattern. provides a simple placeholder object for a more complex object that is in some way time-consuming or expensive to instantiate.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset