| By Bill Wagner | Article Rating: |
|
| April 17, 2006 02:00 PM EDT | Reads: |
16,368 |
There's only one difficulty with design patterns in general: Patterns reuse design elements not code elements. To save time I want to be able to reuse both. Some patterns don't require generics to create a reusable coding solution. For example, the INotifyPropertyChanged interface in the 2.0 .NET Framework provides the hooks for the Observer pattern. If you implement the INotifyPropertyChanged interface on any class, it can easily serve as the Subject in the Observer pattern. (See Design Patterns for more details).
The Proxy pattern provides a wrapper around objects that are expensive to create or keep in memory. Until the item is needed, the proxy serves as a placeholder for that item. Once the application requests the expensive object, the proxy creates and initializes the target. In the sample application, you'll use the proxy pattern to wrap the images before they're loaded. The CollageImage class already uses two different concrete proxy implementations: one for the full image and one for the thumbnail. It's a bit more complicated to create a generic proxy, but the payoffs are larger. In practice, creating generic classes will often require this amount of thinking to get to the point where you can simply reuse an implementation.
Creating Generic Implementations
The design
pattern for a proxy is simple: your class contains a wrapper for an
expensive resource, and that expensive resource is loaded (or
initialized) on-demand.
The specific implementation for images is simple. The CollageImage.loadImage method already does just that:
private void loadImage()
{
if ( theImage == null )
theImage = new Bitmap(path);
}
If the embedded image hasn't been created, it's loaded from disk and then we keep the image around in memory. The thumbnail image has a slightly different specific implementation of the proxy. In this case, the thumbnail is created from the full size image.
You can build the generic class that will let you create any expensive object from an arbitrary set of parameters. Each time you reuse it, you have to write one new method: the method that initializes the expensive resource from its parameters. The pathway from a specific implementation to the generic class takes two steps. The first step is to separate any specific algorithms for the general algorithms. Once that is done, you turn the general algorithms into the generic class. Finally, you use the specific implementations as the type parameters of the generic class.
We'll start by creating an Image Proxy implementation that separates the specific implementation of loading an image from the general Proxy code. The one obvious method specific to an Image Proxy is the code to load the image from a file name. It's a simple one-line method:
public static Image Reconstitute(string imagePath)
{
return new Bitmap(imagePath);
}
The ImageProxy class uses this method as a delegate to load the image. (See Listing 4.) Let's look at the internals of the ImageProxy class and see how we can modify it to be a generic implementation:
- It stores three bits of information: The target image, the path to the target image, and a reference to the delegate that creates an image from the path.
- It's got two public methods: the constructor and a public property to retrieve the target. Notice that anything specific to the Image class is encapsulated in the Reconstitute method.
- The reason to factor out the Reconstitute method into a different class and use a delegate is that a delegate provides the best method to separate the general logic from the specific logic that loads the target image.
A little simple refactoring on the ImageProxy class gives us Listing 5. To instantiate the generic image proxy, you declare the proper variable type:
private Proxy<Image,string> theImage;
And then instantiate it with the proper variables:
theImage = new Proxy<Image, string>
(path, new Proxy<Image,string>.proxyLoader
(ImageBuilder.Reconstitute));
You can use this proxy class to generate the proxy for the thumbnail image. There are a couple different ways to build the thumbnail for the images. You can build the Thumbnail from the instantiation of the image proxy. That's got a couple of disadvantages. The first is that the code is somewhat more complicated:
private Proxy<Image,Proxy<Image, string> >
thumbNail;
thumbNail = new Proxy<Image,
Proxy<Image, string>>
(theImage, new Proxy<Image,
Proxy<Image, string>>.proxyLoader
(ThumbnailBuilder.Create-Thumbnail));
I show this just so you can see that there's nothing special about the types used to build the thumbnails. You can use any types that satisfy the declared constraints, including other generics to instantiate a generic class.
The second issue is more important. You would load all the full-size images just to view all the thumbnails. It's likely (at least in this application) that a user will want to browse through the thumbnails before loading the full image. So, let's build a different form of the thumbnail proxy: one that creates the thumbnail from the image on disk and discards the full-size image. That just takes a different method for the delegate:
public static Image LoadThumbnail(string src)
{
using (Image fullSize = new Bitmap(src))
return fullSize.GetThumbnailImage(150, 150,
new Image.GetThumbnailImageAbort(uselessDelegate),
IntPtr.Zero);
}
Once this is in place, the user can browse for images and the proxy will create the thumbnail and discard the full image. The full image is only used in memory when the user has added it to his or her current collage.
Conclusion
In some sense, generics suffer from
being so well suited to collections: that's almost the only use case
most people ever see. But, generics are really a general-purpose tool
that can be used for many different functions in your applications.
Sometimes you'll create generic classes to implement common bits of
logic, other times you can use generics to provide the mechanism to
collaborate between objects of different types. It's a little more work
to create these reusable blocks, but the payoff is more than worth it:
more functionality, without an increase in code to maintain. Learn to
see where these opportunities exist, and create the code to match. The
payback is immediate and continues to grow. You'll find that once you
have even a small library of generic classes, you'll reuse them often
and save even more time. And well-designed generic classes can be used
in almost countless ways. I've shown you how to spot specific instances
of algorithms that could become generic classes and how to modify those
algorithms to match the syntax necessary to create generic classes.
Published April 17, 2006 Reads 16,368
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Bill Wagner
A frequent writer and speaker, Bill's work is published in ASP.NET Pro and Visual Studio Magazine. He is the author of C# Core Language Little Black Book and Effective C#. You can reach Bill at wwagner@srtsolutions.com.
- Kindle 2 vs Nook
- Confessions of a Ulitzer Addict
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Windows 7 – Microsoft’s First Step to the Cloud
- Cloud Expo and the End of Tech Recession
- Jill Tummler Singer, Deputy CIO of CIA, Keynotes at GovIT Expo
- Reality Check at the Cloud Computing Expo
- Visual Studio 2010 Is Cloud Friendly
- Fired SCO CEO Fires Back
- Kindle 2 vs Nook
- The Difference Between Web Hosting and Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Confessions of a Ulitzer Addict
- Wave on Ulitzer: Confessions of a Google Wave Fanboy
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Cloud Computing Best Practices
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Eval JavaScript in a Global Context
- Windows 7 – Microsoft’s First Step to the Cloud
- Google Maps and ASP.NET
- Crystal Reports XI & How It Has Changed
- Converting VB6 to VB.NET, Part I
- Creating Controls for.NET Compact Framework in Visual Studio 2005
- Where Are RIA Technologies Headed in 2008?
- How to Write High-Performance C# Code
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Implementing Tab Navigation with ASP.NET 2.0
- i-Technology Photo Exclusive: Bill Gates & Steve Jobs In "Nerds"
- .NET Archives: Getting Reacquainted with the Father of C#
- i-Technology Viewpoint: "SOA Sucks"
- Programmatically Posting Data to ASP .NET Web Applications



























