The Facade Pattern

When we put up a facade, we present an outward appearance to the world that may conceal a very different reality. This was the inspiration for the name behind the next pattern we’re going to review: the Facade pattern. This pattern provides a convenient higher-level interface to a larger body of code, hiding its true underlying complexity. Think of it as simplifying the API being presented to other developers, something that almost always improves usability (Figure 9-8).

Facade pattern

Figure 9-8. Facade pattern

Facades are a structural pattern that can often be seen in JavaScript libraries such as jQuery where, although an implementation may support methods with a wide range of behaviors, only a “facade,” or limited abstraction of these methods, is presented to the public for use.

This allows us to interact with the Facade directly rather than the subsystem behind the scenes. Whenever we use jQuery’s $(el).css() or $(el).animate() methods, we’re actually using a Facade: the simpler public interface that lets us avoid having to manually call the many internal methods in jQuery core required to get some behavior working. This also circumvents the need to manually interact with DOM APIs and maintain state variables.

The jQuery core methods should be considered intermediate abstractions. The more immediate burden to developers is the DOM API, and facades are what make the jQuery library so easy to use.

To build on what we’ve learned, the Facade pattern both simplifies the interface of a class and decouples the class from the code that uses it. This gives us the ability to indirectly interact with subsystems in a way that can sometimes be less prone to error than accessing the subsystem directly. A Facade’s advantages include ease of use and often a small-sized footprint in implementing the pattern.

Let’s take a look at the pattern in action. This is an unoptimized code example, but here we’re using a Facade to simplify an interface for listening to events across browsers. We do this by creating a common method that can be used in one’s code which does the task of checking for the existence of features so that it can provide a safe and cross-browser compatible solution.

var addMyEvent = function( el,ev,fn ){

   if( el.addEventListener ){
            el.addEventListener( ev,fn, false );
      }else if(el.attachEvent){
            el.attachEvent( "on" + ev, fn );
      } else{
           el["on" + ev] = fn;
    }

};

In a similar manner, we’re all familiar with jQuery’s $(document).ready(..). Internally, this is actually powered by a method called bindReady(), which is doing this:

bindReady: function() {
    ...
    if ( document.addEventListener ) {
      // Use the handy event callback
      document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

      // A fallback to window.onload, that will always work
      window.addEventListener( "load", jQuery.ready, false );

    // If IE event model is used
    } else if ( document.attachEvent ) {

      document.attachEvent( "onreadystatechange", DOMContentLoaded );

      // A fallback to window.onload, that will always work
      window.attachEvent( "onload", jQuery.ready );
               ...

This is another example of a Facade, in which the rest of the world simply uses the limited interface exposed by $(document).ready(..) and the more complex implementation powering it is kept hidden from sight.

Facades don’t just have to be used on their own, however. They can also be integrated with other patterns, such as the Module pattern. As we can see below, our instance of the Module pattern contains a number of methods that have been privately defined. A Facade is then used to supply a much simpler API to accessing these methods:

var module = (function() {

    var _private = {
        i:5,
        get : function() {
            console.log( "current value:" + this.i);
        },
        set : function( val ) {
            this.i = val;
        },
        run : function() {
            console.log( "running" );
        },
        jump: function(){
            console.log( "jumping" );
        }
    };

    return {

        facade : function( args ) {
            _private.set(args.val);
            _private.get();
            if ( args.run ) {
                _private.run();
            }
        }
    };
}());
 
 
// Outputs: "current value: 10" and "running"
module.facade( {run: true, val:10} );

In this example, calling module.facade() will actually trigger a set of private behavior within the module, but again, the users aren’t concerned with this. We’ve made it much easier for them to consume a feature without needing to worry about implementation-level details.

Notes on Abstraction

Facades generally have few disadvantages, but one concern worth noting is performance. Namely, one must determine whether there is an implicit cost to the abstraction a Facade offers to our implementation and, if so, whether this cost is justifiable. Going back to the jQuery library, most of us are aware that both getElementById("identifier") and $("#identifier") can be used to query an element on a page by its ID.

Did you know however that getElementById() on its own is significantly faster by a high order of magnitude? Take a look at this jsPerf test to see results on a per-browser level: http://jsperf.com/getelementbyid-vs-jquery-id. Now of course, we have to keep in mind that jQuery (and Sizzle, its selector engine) are doing a lot more behind the scenes to optimize our query (and that a jQuery object, not just a DOM node is returned).

The challenge with this particular Facade is that in order to provide an elegant selector function capable of accepting and parsing multiple types of queries, there is an implicit cost of abstraction. The user isn’t required to access jQuery.getById("identifier") or jQuery.getbyClass("identifier") and so on. That said, the trade-off in performance has been tested in practice over the years and, given the success of jQuery, a simple Facade actually worked out very well for the team.

When using the Facade pattern, try to be aware of any performance costs involved and make a call on whether they are worth the level of abstraction offered.

Get Learning JavaScript Design Patterns now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.