When we put up a facade, we present an outward appearance to the world which 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 which almost always improves usability.
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 avoids us having to manually call the many internal methods in jQuery core required to get some behavior working. This also avoids 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 it also decouples the class from the code that utilizes 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 size-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 utilizing a Facade to simplify an interface for listening to events cross-browser. 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.
// A fallback to window.onload, that will always work
window.attachEvent( “onload”, jQuery.ready );
This is another example of a Facade, where 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 patterns contains a number of methods which have been privately defined. A Facade is then used to supply a much simpler API to accessing these methods:
In this example, calling module.facade() will actually trigger a set of private behavior within the module, but again, the user isn’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 pattern, try to be aware of any performance costs involved and make a call on whether they are worth the level of abstraction offered.