Karl Seguin

Sponsors

The Lounge

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Foundations of Programming - pt 9 - Proxy This and Proxy That
Few keywords are as simple yet amazingly powerful as virtual in C# (overridable in VB.NET). When you mark a method as virtual you allow an inheriting class to override the behavior. Without this functionality inheritance and polymorphism wouldn't be of much use. A simple example, slightly modified from Programming Ruby (ISBN: 978-0-9745140-5-5), which has a KaraokeSong overrides a Song's to_s (ToString) function looks like:
class Song
   def to_s
      return sprintf("Song: %s, %s (%d)", @name, @artist, @duration)
   end
end

class KaraokeSong < Song
   def to_s
      return super + " - " @lyrics
   end
end

The above code shows how the KaraokeSong is able to build on top of the behavior of its base class. Specialization isn't just about data, it's also about behavior!

Even if your ruby is a little rusty, you might have picked up that the base to_s method isn't marked as virtual. That's because many languages, including Java, make methods virtual by default. This represents a fundamental differing of opinion between the Java language designers and the C#/VB.NET language designers. In C# methods are final by default and developers must explicitly allow overriding (via the virtual keyword). In Java, methods are virtual by default and developers must explicitly disallow overriding (via the final keyword).

Typically virtual methods are discussed with respect to inheritance of domain models. That is, a KaraokeSong which inherits from a Song, or a Dog which inherits from a Pet. That's a very important concept, but it's already well documented and well understood. Therefore, we'll examine virtual methods for a more technical purpose: proxies.

Proxy Domain Pattern

A proxy is something acting as something else. In legal terms, a proxy is someone given authority to vote or act on behalf of someone else. Such a proxy has the same rights and behaves pretty much like the person being proxied. In the hardware world, a proxy server sits between you and a server you're accessing. The proxy server transparently behaves just like the actual server, but with additional functionality - be it caching, logging or filtering. In software, the proxy design pattern is a class that behaves like another class. For example, if we were building a task tracking system, we might decide to use a proxy to transparently apply authorization on top of a task object:

public class Task
{  
   public static Task FindById(int id)
   {
      return TaskRepository.Create().FindById(id);
   }   

   public virtual void Delete()
   {
      TaskRepository.Create().Delete(this);
   }
}
public class TaskProxy : Task
{
   public override void Delete()
   {
      if (User.Current.CanDeleteTask())
      {
         base.Delete();
      }
      else
      {
         throw new PermissionException(...);
      }
   }
}

Thanks to polymorphism, FindById can return either a Task or a TaskProxy. The calling client doesn't have to know which was returned - it doesn't even have to know that a TaskProxy exists. It just programs against the Task's public API.

Since a proxy is just a subclass that implements additional behavior, you might be wondering if a Dog is a proxy to a Pet. Proxies tend to implement more technical system functions (logging, caching, authorization, remoting, etc) in a transparent way. In other words, you wouldn't declare a variable as TaskProxy - but you'd likely declare a Dog variable. Because of this, a proxy wouldn't add members (since you aren't programming against its API), whereas a Dog might add a Bark method.

Interception

The reason we're exploring a more technical side of inheritance is because two of the tools we've looked at so far, RhinoMocks and NHibernate, make extensive use of proxies - even though you might not have noticed. RhinoMocks uses proxies to support its core record/playback functionality. NHibernate relies on proxies for its optional lazy-loading capabilities. We'll only look at NHibernate, since it's easier to understand what's going on behind the covers, but the same high level pattern applies to RhinoMocks.

(A side note about NHibernate. It's considered a frictionless or transparent O/R mapper because it doesn't require you to modify your domain classes in order to work. However, if you want to enable lazy loading, all members must be virtual. This is still considered frictionless/transparent since you aren't adding NHibernate specific elements to your classes - such as inheriting from an NHibernate base class or sprinkling NHibernate attributes everywhere.)

Using NHibernate there are two distinct opportunities to leverage lazy loading. The first, and most obvious, is when loading child collections. For example, you may not want to load all of a Model's Upgrades until they are actually needed. Here's what your mapping file might look like:

<class name="Model" table="Models">
   <id name="Id" column="Id" type="int">
      <generator class="native" />
   </id>
   ...
   <bag name="Upgrades" table="Upgrades" lazy="true" >
      <key column="ModelId" />
      <one-to-many class="Upgrade" />
   </bag>      
</class>

By setting the lazy attribute to true on our bag element, we are telling NHibernate to lazily load the Upgrades collection. NHibernate can easily do this since the it returns it uses its own collection types (which all implement standard interfaces, such as IList, so to you, it's transparent).

The second, and far more interesting, usage of lazy loading is for individual domain objects. The general idea is that sometimes you'll want whole objects to be lazily initialized. Why? Well, say that a sale has just been made. Sales are associated with both a sales person and a car model:

Sale sale = new Sale();
sale.SalesPerson = session.Get<SalesPerson>(1);
sale.Model = session.Get<Model>(2);
sale.Price = 25000;
session.Save(sale);

Unfortunately, we've had to go to the database twice to load the appropriate SalesPerson and Model - even though we aren't really using them. The truth is all we need is their ID (since that's what gets inserted into our database), which we already have.

By creating a proxy, NHibernate lets us fully lazy-load an object for just this type of circumstance. The first thing to do is change our mapping and enable lazy loading of both Models and SalesPeoples:

<class name="Model" table="Models" lazy="true" proxy="Model">...</class>

<class name="SalesPerson" table="SalesPeople" 
      lazy="true" proxy="SalesPerson ">...</class>

The proxy attribute tells NHibernate what type should be proxied. This will either be the actual class you are mapping to, or an interface implemented by the class. Since we are using the actual class as our proxy interface, we need to make sure all members are virtual - if we miss any, NHibernate will throw a helpful exception with a list of non-virtual methods. Now we're good to go:

Sale sale = new Sale();
sale.SalesPerson = session.Load<SalesPerson>(1);
sale.Model = session.Load<Model>(2);
sale.Price = 25000;
session.Save(sale);

Notice that we're using Load instead of Get. The difference between the two is that if you're retrieving a class that supports lazy loading, Load will get the proxy, while Get will get the actual object. With this code in place we're no longer hitting the database just to load IDs. Instead, calling Session.Load<Model>(2) returns a proxy - dynamically generated by NHibernate. The proxy will have an id of 2, since we supplied it the value, and all other properties will be uninitialized. Any call to another member of our proxy, such as sale.Model.Name will be transparently intercepted and the object will be just-in-time loaded from the database.

Just a note, NHibernate's lazy-load behavior can be hard to spot when debugging code in Visual Studio. That's because VS.NET's watch/local/tooltip actually inspects the object, causing the load to happen right away. The best way to examine what's going on is to add a couple breakpoints around your code and check out the database activity either through NHibernate's log, or SQL profiler.

Hopefully you can imagine how proxies are used by RhinoMocks for recording, replaying and verifying interactions. When you create a partial you're really creating a proxy to your actual object. This proxy intercepts all calls, and depending on which state you are, does its own thing. Of course, for this to work, you must either mock an interface, or a virtual members of a class.

In This Chapter

In chapter 6 we briefly covered NHibernate's lazy loading capabilities. In this chapter we expanded on that discussion by looking more deeply at the actual implementation. The use of proxies is common enough that you'll not only frequently run into them, but will also likely have good reason to implement some yourself. I still find myself impressed at the rich functionality provided by RhinoMock and NHibernate thanks to the proxy design pattern. Of course, everything hinges on you allowing them to override or insert their behavior over your classes. Hopefully this chapter will also make you think about which of your methods should and which shouldn't be virtual. I strongly recommend that you take a look at the following articles/posts to better understand the virtual by default vs final by default points of view:


Posted Wed, Jun 18 2008 8:32 AM by karl
Filed under:

[Advertisement]

Comments

Dew Droplet - June 18, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Droplet - June 18, 2008 | Alvin Ashcraft's Morning Dew
on Wed, Jun 18 2008 9:46 AM

Pingback from  Dew Droplet - June 18, 2008 | Alvin Ashcraft's Morning Dew

Against All Authority » Blog Archive » Foundations of Programming - pt 9 - Proxy This and Proxy That wrote Against All Authority &raquo; Blog Archive &raquo; Foundations of Programming - pt 9 - Proxy This and Proxy That
on Wed, Jun 18 2008 11:11 PM

Pingback from  Against All Authority  &raquo; Blog Archive   &raquo; Foundations of Programming - pt 9 - Proxy This and Proxy That

Reflective Perspective - Chris Alcock » The Morning Brew #118 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #118
on Thu, Jun 19 2008 2:39 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #118

beran wrote re: Foundations of Programming - pt 9 - Proxy This and Proxy That
on Fri, Jun 20 2008 4:02 AM

Hey, thanks for articles, much appreciated!

Just note, the links to posts by Eric Gunnerson are same, so we only got one post.

Dave Mellors wrote Learning how to program - again!
on Sun, Jun 22 2008 12:00 PM

The problem with not programming all the time is keeping up with the constant developments in programming

Fregas wrote re: Foundations of Programming - pt 9 - Proxy This and Proxy That
on Sat, Dec 20 2008 11:45 AM

Karl,

Why is virtual necessary for NHibernate?  I assume that they are using reflection to create a proxy that inherits from the real class.  Is this some limitation of reflection?

craig

Jeremy D. Miller wrote re: Foundations of Programming - pt 9 - Proxy This and Proxy That
on Sat, Dec 20 2008 12:18 PM

@Fregas,

It's a limitation/feature of .Net itself, and nothing to do with reflection.  The dynamic proxy is creating a subclass of the concrete type on the fly.  Any member that is marked as lazy loaded has to be virtual so that the dynamic proxy class can override that property to set up the lazy loading.