Chapter 20. The Proxy Pattern

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

There are several cases where a Proxy can be useful.

  1. An object, such as a large image, takes a long time to load.
  2. The results of a computation take a long time to complete, and you need to display intermediate results while the computation continues.
  3. The object is on a remote machine, and loading it over the network may be slow, especially during peak network load periods.
  4. The object has limited access rights, and the proxy can 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 may set up a number of objects that may not all be used right away. In that case, the proxy can load the real object only when it is needed.

Let’s consider the case of a large image that a program must load and display. When the program starts, there must be some indication that an image is to be displayed so that the screen lays out correctly, but 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 even 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 process.

Sample Code

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


private void init() {
       imgProxy = new ImageProxy ();
}
//-----
public Form1() {
       InitializeComponent();
       init();
       }
//-----
private void button1_Click(object sender, EventArgs e) {
       Pic.Image = imgProxy.getImage ();
}

Note that we create the instance of the ImageProxy just as we would have for an Image. The ImageProxy class sets up the image loading and creates an Imager object to follow the loading process. It returns a class that implements the Imager interface.


public interface Imager   {
      Image getImage() ;
}

In this simple case, the ImageProxy class just delays five seconds and then switches from the preliminary image to the final image. It does this using an instance of the Timer class. Timers are handled using a TimerCallback class that defines the method to be called when the timer ticks. This is very similar to the way we add other event handlers. And this callback method, timerCall, sets the done flag and turns off the timer.


public class ImageProxy    {
      private bool done;
      private Timer timer;
      //-----
      public ImageProxy()                {
      //create a timer thread and start it
             timer = new Timer (
                 new TimerCallback (timerCall), this, 5000, 0);
      }
      //-----
      //called when timer completes
      private void timerCall(object obj) {
             done = true;
             timer.Dispose ();
      }
      //-----
      public Image getImage() {
             Imager img;
             if (done)
                    img = new FinalImage ();
             else
                    img = new QuickImage ();
             return img.getImage ();
      }
}

We implement the Imager interface in two tiny classes we called QuickImage and FinalImage. One gets a small gif image and the other a larger (and presumably slower) jpeg image. In C#, Image is an abstract class, and the Bitmap, Cursor, Icon, and Metafile classes are derived from it. So the actual class we will return is derived from Image. The QuickImage class returns a Bitmap from a gif file, and the final image a jpeg file.


public class QuickImage : Imager {
      public QuickImage() {}
      public Image getImage() {
             return new Bitmap ("Box.gif");
      }
}
//------------
public class FinalImage :Imager {
      public FinalImage() {}
      public Image getImage() {
             return new Bitmap("flowrtree.jpg");
      }
}

When you go to fetch an image, you initially get the quick image, and after five seconds, if you call the method again, you get the final image. The program’s two states are illustrated in Figure 20-1.

Figure 20-1. The proxy image display on the top is shown until the image loads as shown on the bottom.

image

Proxies in C#

You see more proxylike behavior in C# than in other languages because it is crafted for network and Internet use. For example, the ADO.NETdatabase connection classes are all effectively proxies.

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 there is no reason to make a copy yet. 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 be a great time and space saver when objects do not always change after they are instantiated.

Comparison with Related Patterns

Both the Adapter and the Proxy 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 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

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

Program on the CD-ROM

image

Summary of Structural Patterns

Part III covered the following structural patterns.

The Adapter pattern is used to change the interface of one class to that of another one.

The Bridge pattern is designed to separate a class’s interface from its implementation so you can vary or replace the implementation without changing the client code.

The Composite pattern is a collection of objects, any one of which may be either itself a Composite or just a leaf object.

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

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

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

The 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