Recently one of the 8th Light apprentices said that he was using the Repository pattern in a project and asked me how it differed from the “Gang of Four’s” Proxy pattern. I confessed that I hadn’t read through all of the patterns in Design Patterns: Elements of Reusable Object-Oriented Software, so this was an excellent chance to read up on the Proxy pattern (and get back into blogging).

The short answer to his question can be found from the GoF’s stated intent for the Proxy Pattern:

Provide a surrogate or placeholder for another object to control access to it.

The Repository class from my post on the pattern never really controls access to the underlying repositories— it behaves only as a simple pointer and never acts as a surrogate or placeholder for the underlying data stores. The Repository class never stores any data itself, never has any affect on the data being sent to the datastore, and is never responsible for the creation of any datastore. It simply points to data stores with no regard for what they are. They could be in-memory relational databases, or flat-files— much like the honey badger, my Repository class doesn’t care. Furthermore, in the ‘Applicability’ section of the GoF Proxy pattern chapter, it states that the Proxy is used specifically when something more powerful than a simple pointer is required, but my Repository is never anything more than that.

The Long Answer

There is, however, one statement in the GoF book that could easily be interpreted as a similarity between the two patterns. In fact, the first time I ride it I had to ask whether or not my implementation of the Repository pattern was in fact just a Proxy.

The GoF list the first motivation for using the Proxy pattern as “deferring the full cost of an object’s creation until we actually need to use it”. Deferment was certainly part of my motivation in using the Repository pattern, however that deferment had everything to do with deferring a decision about an implementation detail (the database)- and nothing to do with deferring creation. I still had to create an in-memory datastore and implement all of the methods that I would need from a database. So for all intents and purposes my in-memory datastore is a full-fledged database. I might have even discovered that my app never needed anything more than that.

Of course, I did know that I was going to need some sort of persistence beyond an in-memory datastore, so I think my implementation could be interpreted as a figurative proxy, even if not a literal one. What it did was allow me to determine what I was going to really need from my datastore— as well as provide a lightweight and fast database to test against.

So Now That We Know What a Proxy Isn’t…

There are a few other statements in the GoF book that highlight key differences between my implementation of the Repository pattern and the Proxy pattern, and through those differences we can understand a little more about what a Proxy is.

As I mentioned earlier, the GoF state that the “Proxy is applicable whenever there is a need for a more versatile or sophisticated reference to and object than a simple pointer”. Examples of that versatility and power include:

  • Virtual proxy: This also falls under the category of “deferring creation”. The example the GoF use for this is when a proxy can provide a smaller version of an image file that will get the job done instead of instantiating an image at its full resolution. I recently participated in a project where we were using caching on a proxy
  • Remote Proxy: this is a proxy that represents something in a local address space instead of having to make the call to a remote object or service. I recently participated in a project where we used cached data on a proxy to save ourselves the expensive call to an external service.
  • Protection Proxy: exactly as it sounds, in this case the proxy is useful when different access rights need to be granted.
  • Smart Reference: in this case the proxy performs some additional behavior before calling the actual object. Examples from the GoF include counting references to an object to manage memory or checking that the actual object is properly locked so that you can make sure nothing else changes it.

Wrap-Up

Ultimately, the difference between my implementation of the Repository pattern and the GoF Proxy pattern boils down to the extra behavior that a Proxy does besides “pointing”. Although I’d heard from others that the “Design Patterns” can be a bit intimidating, it’s still one of those books that every programmer should own and the Proxy chapter is a good one with lots of concrete examples. Since proxies are something we see with regularity “in real life” I recommend checking it out and reading a little deeper into the details.