13.8.10

Filter Overload Pattern

Assume you are working with the toggle function in jQuery and that you want to do something different with it. This would require writing a different plugin and naming it differently or changing the default toggle function.

In the simplest terms, the pattern starts with a function:
function stuff(s){
    if (typeof s == 'string')
      doStuffWithAString(s)
    else throwOrIgnore();
  }

Maybe you can't change the source code, or maybe you obsessively want to ultra-modularize your code. Either way, assume you want to use the same name to keep your source code as semantic as possible. Here is how I would do it:

// redefine function
  var _old_stuff = stuff;
  stuff = function(b){
    // check for special case which should be overloaded here
    if (typeof b == 'boolean')
      // new behavior
      doStuffWithABoolean(b);
    // old behavior: call previously defined function.
    else _old_stuff(b);
  };

If you happen to mistakenly call the block twice, you will throw the function into a self-referential (endless) loop.

With this pattern, you can build functions that specialize in delegating functions by argument patterns, akin to classical Java method overloading. If you will be handling many patterns, it may eventually be interesting to use only one index delegator instead of a cascading pattern.

To illustrate how amusing it is to write overcomplicated code, consider the following

Mega Super Ultimate Listener Overload Pattern of Awesomeness


The interface is the only public function:
function transmogrify(){
  // using this function as a dictionary or map:
  for (var filter in transmogrify.filters){
    // filter functions return the name of the method to call
    var key = transmogrify.filters[filter].apply(this, arguments);
    if (key) 
      transmogrify.methods[key].apply(this, arguments);
  }
}

This is the extension mechanism. The filter can check argument arity, type, validity, etc.
transmogrify.filters.zap = function(str, num){
  if (typeof str == 'string' && typeof num == 'num')
    return 'zip';
};
transmogrify.methods.zip = function(){
  // there be beautiful code herein
};

I know you want a function that does these two things in one go; a meta-meta-meta function. Maybe later.

No comments: