Killing Switch Statements With A Registry: An Example And Screencast

In my video on the SOLID principles applied to JavaScript, I showed a quick transformation from using a switch statement to using a registry instead, with the Open-Closed principle as the impetus for moving in that direction. It’s a good trick to get more flexibility out of your code by letting you add as many actions as needed, without having to change the way things work internally. You can reduce the “ugly” factor of a switch statement, create code that is easier to read, and claim your SOLID principles badge of honor all in one move. That’s a pretty sweet deal, if you ask me. 

Open To Change, Closed To Modification

The Open-Closed Principle (OCP) says that code should be opened to change in behavior, but closed to modification.

As I said in the talk, the best example of this is to look at hardware. Nearly every computing and mobile device out there has some sort of USB connection on it, these days. Plugging a USB device in to a laptop or desktop computer is a great example of how hardware is open to extension and change in behavior, without being required to change the existing hardware. You just plug the thumb drive, headset, camera, network adapter, or whatever it is in to the USB port and now your computer has additional behavior available. You’ve changed the system without changing the existing hardware. 

Code works the same way. When we provide plugins, extensions, interface / protocol implementations or just pass objects as parameters in our code, we are providing a way to make that code extensible / extendable. We can change the behavior of the code by providing a different implementation of a given interface / protocol, without having to change the code that uses this interface / protocol. This is the essence of the open-closed principle (though there are a lot of other subtleties to watch when it comes to implementations).

OCP As Applied To Switch Statements

Switch statements are a simple way of providing flow control in your program. They let you decide which code is going to run, based on a given value. In the talk, I showed the following switch statement as an example:

var employee = someEmployee;
var action = "view";

switch (action) {
  case "view": 
    showEmployee(someEmployee);
    break;

  case "edit": 
    editEmployee(someEmployee);
    break;
}

function showEmployee(employee){
  var view = new ShowEmployeeForm({
    model: employee
  });
  view.render();
  $("#wizard").html(view.$el);
}

function editEmployee(employee){
  var form = new EditEmployeeForm({
    model: employee
  });
  form.render();
  $("#wizard").html(form.$el);
}

There are several things I don’t like about switch statements, including the inability to change the behavior of the system without digging in to the switch statement itself. Every time you want to add a new thing to execute, you have to change the existing code. This clearly violates OCP by requiring changes to existing code instead of just allowing new behaviors to be added without changing existing code. 

In many (most: probably 9/10 times) cases, a switch statement can be replaced with a registry object.

var viewRegistry = new Registry();
viewRegistry.register("view", showEmployee);
viewRegistry.register("edit", editEmployee);

function showEmployee(employee){
  var view = new ShowEmployeeForm({
    model: employee
  });
  view.render();
  $("#wizard").html(view.$el);
}

function editEmployee(employee){
  var form = new EditEmployeeForm({
    model: employee
  });
  form.render();
  $("#wizard").html(form.$el);
}

var actionName = "view";
var action = viewRegistry.getValue(actionName);

var employee = getSomeEmployee();
action(employee);

This cleans up the ugliness of the switch and also allows you to add and remove behaviors as needed, without changing the internals of the registry or the code that is calling the registry to get things done. 

The Registry Object

The registry object itself is not complex. It takes in a named thing and allows that to be retrieved by name. Whether you call this a registry, a dictionary, a key/value store or whatever you want to call it, the code to implement it in JavaScript is small if not simple.

function Registry(defaultValue){
  this._defaultValue = defaultValue;
  this._values = Object.create(null);
}

Registry.prototype.register = function(name, value){
  this._values[name] = value;
};

Registry.prototype.getValue = function(name){
  var value;
  if (Object.prototype.hasOwnProperty.call(this._values, name)){
    value = this._values[name];
  } else {
    value = this._defaultValue;
  }
  return value;
};

This code gives you all the features you need to completely replace a switch statement, including default values (though, not including fall-through switches, which are a bad idea to begin with). 

I Need More Cowbell

Being able to swap out a switch statement with a registry object is great. But what if you want to know why the registry was built the way it was? What if you need more cowbell?

NewImage

 Well, don’t worry! I’ve got you covered. I built a screencast that covers the registry pattern in more detail, outlining how JavaScript gives us the ability to use simple object literals to store key/value pairs, showing some of the problems that this can cause, and then walking through the construction of the registry object that I used in this presentation. I also walk through some uses of the registry object that we create, including building your own event system by composing the registry in to an Events object. 

NewImage

 If you’re looking for info on how to build a registry, and why you would want to build it the way that I’ve shown, then checkout WatchMeCode Episode 14: The Registry Pattern.

 


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Design Patterns, Javascript, Principles and Patterns, Screencast, WatchMeCode. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • theporchrat

    I have been forgoing switch statements for objects in javascript for a while now, but the Registery object seems like a bit of overkill no? Why bother with a “classical” object here when var registry = {}, registry[key] = fn; registry[key]() would work just fine, and (in my opinion) more transparent? Certainly there are validation cases where the key doesn’t exist etc, but i would imagine many cases don’t have to deal with the “default” case (at least i dont). even then a simple !registry[key] && default(), would work fine, assuming no falsey keys of course.

    To my mind full blown object isn’t much less obtuse then a switch

    • http://mutedsolutions.com Derick Bailey

      flexibility, and avoiding pitfalls associated with object literals as hashes: http://www.devthought.com/2012/01/18/an-object-is-not-a-hash/

      • theporchrat

        definitely true if you are exposing some sort of Registry object to outside consumers, say as a module.

        I’ve also read the article you’ve posted, its certainly correct but much of the pitfalls described aren’t likely to apply to an object as a switch replacement, where the “hash” is very limited size (i would think that a switch with 20 paths is indicative of a bad design choice). what is the likelihood of a programmer pushing a hash key that conflicts with base properties that also breaks functionality, in the context of using the object as a switch?

        Most of the “Objects are not hashes” pitfalls are more applicable to a hash with an unknown size and where the keys are unknown. A switch statement is mostly the opposite of that, known size, self-determined keys.

        Wondering at the cost/benefit of making a full object, to protect against edge case pitfalls. perhaps there is almost no overhead, in which case lets go for it.

        not trying to nitpick, or even disagree, just an poking at the concept here that is outside my normal instincts, thanks!

        • http://mutedsolutions.com Derick Bailey

          i see what you’re saying now. i was definitely focused on the idea of exposing the object to other modules / code, but if you’re doing something internal / private in your code, then a simple object literal is not a bad option.

  • http://wizardsofsmart.net/ panesofglass

    Thanks for the post! I used this method 5 or 6 years ago and faced endless amounts of ridicule. I agree it is a much better approach. I think I first picked up the trick while learning F#, actually, and like theporchrat, I used a hashtable (actually an IDictionary<string, Action<T>>).

  • Geoff Mazeroff

    I’ve used this pattern a few times as well to deal with nasty switch statements. It may go by the other name of “strategy.” I really liked your analogy of OCP — you don’t need to build another computer just to add a webcam.

    • http://mutedsolutions.com Derick Bailey

      yeah, the registry / dictionary idea can definitely be used for a Strategy Pattern implementation. there’s a lot of other ways to do a Strategy Pattern, too, but this definitely works. :)

  • Dale

    Are you implying that switch statements violate open/closed? If so, I would have to disagree. They violate a lot of other good OOP principles and are a bad smell in code but I think you’ve misinterpreted the open/closed principle.

  • mikestoddart

    I use this pattern quite a bit in both Javascript, Python and Java. I find it tidies the code up nicely and is easier to maintain.