Wednesday, June 3, 2009

Feel the bliss of the design pattern InstanceRegistry

The InstanceRegistry pattern values loose coupling between objects. This pattern is as simple as the Singleton pattern, but with the InstanceRegistry pattern your objects stay simple, replaceable and testable - even you manager objects.

Your choice: Tightly or Loosely?

"Until somone changes my mind, I will always use Pete Bong for plumbing, Tira Donk for carpentry and Rolli Streak for decorations." - Foo

Above statement from object Foo raises the following dependency concerns:  
  • Foo's abilities cannot be tested without Pete Bong, Tira Donk and Rolli Streak,
  • Foo's abilities cannot be used without Pete Bong, Tira Donk and Rolli Streak, and
  • Foo needs to changed, if Pete Bong, Tira Donk or Rolli Streak needs to be replaced.

"Whenever I need handywork done, I just lookup an available plumber, carpenter or decorator."  - Bar

In constrast to Foo, above statement tells us that Bar has the following dependency strong points:
  • Bar's abilities can be tested with any plumber, carpenter and decorator,
  • Bar's abilities can be used with any plumber, carpenter and decorator, and
  • Bar is satisfied to use an externally defined plumber, carpenter and decorator.

Now, should you at this point be in doubt which object to prefer - Foo or Bar - then I fear that the rest of this entry does not have more to offer. On the other hand, if you now are thinking in the lines of 'I like a Bar, but how expensive is it?' then hang on for the bliss...

Your Battle: Foo vs Bar

Imagine Foo would have code that looked something like this:
PeteBong plumber = (PeteBong) PeteBong.getInstance();
This kind of code is pretty common, causes the previously mentioned concerns, but also has the very nice feature that the reference to PeteBong is fetched when needed. Last mentioned feature is possible, since PeteBong is globally available as a static reference via the Singleton pattern. 

Now a Bar version of this code uses the InstanceRegistry pattern:
IPlumber plumber = (IPlumber)InstanceRegistry.getInstance('IPlumber');
or even better
IPlumber plumber = instanceRegistry.getInstance<IPlumber>();
Here Bar is tightly coupled to an InstanceRegistry that is basically just a map between ids and object instances. Whether this id is a string or a type is up to you, but in the later version you have the ability ensure loosely coupled objects by only accepting interfaces as ids. Please note that the getInstance method simply looks up a reference to an object that has registered itself in the InstanceRegistry and, thus, become globally available to other objects. The InstanceRegistry does NOT create new instances.

Since Bar is using the InstanceRegistry pattern it has the following properties:
  • Bar can be tested with mock up implementations of its dependent interfaces e.g. IPlumber,
  • Bar can be used with any implementation of its dependent interfaces e.g. IPlumber, and
  • Bar is designed work with objects that may change implementation, but not specification. 
Your Exercise: An InstanceRegistry implementation

Here are some considerations to do when creating an InstanceRegistry implementation. I hope the missing implementation details will become some nice discussion subjects, and that you will have fun making this pattern yours.
  • Decide whether to make an InstanceRegistry interface or not, and imagine how it would be used,
  • Decide how to pass your InstanceRegistry implementation reference around,
  • Decide on methods and arguments for adding and removing the object instances that can be be fetched via the getInstance method, and
  • Decide on other useful methods that the InstanceRegistry might have.
Enjoy the bliss, give feedback and start discussions.


1 comment: