AJAX In Action [46]
or the native object subsystem; it only needs to understand the net.ContentLoader() constructor. The Façade pattern
For both getLeft() and new net.ContentLoader(), the code that does the object detection is ugly and tedious. By defining a function to hide it from the rest of our code, we are making the rest of the code easier to read and isolating the objectdetection code in a single place. This is a basic principle in refactoring—don’t repeat yourself, often abbreviated to DRY. If we discover an edge case that our object-detection code doesn’t handle properly, then fixing it once rolls that change out to all calls to discover the left coordinate of a DOM element, create an XML Request object, or whatever else we are trying to do.
In the language of design patterns, we are using a pattern known as Façade. Façade is a pattern used to provide a common access point to different implementations of a service or piece of functionality. The XMLHttpRequest object, for example, offers a useful service, and our application doesn’t really care how it is delivered as long as it works (figure 3.1).
In many cases, we also want to simplify access to a subsystem. In the case of getting the left-edge coordinate of a DOM element, for example, the CSS spec provided us with a plethora of choices, allowing the value to be specified in pixels, points, ems, and other units. This freedom of expression may be more than we need. The getLeft() function in listing 3.2 will work as long as we are using pixels as the unit throughout our layout system. Simplifying the subsystem in this way is another feature of the Façade pattern.
The Adapter pattern
A closely related pattern is Adapter. In Adapter, we also work with two subsystems that perform the same function, such as the Microsoft and Mozilla approaches to getting an XMLHttpRequest object. Rather than constructing a new Façade for each to use, as we did earlier, we provide an extra layer over one of the subsystems that presents the same API as the other subsystem. This layer is known as the Adapter. The Sarissa XML library for Ajax, which we will discuss in section 3.5.1, uses the Adapter pattern to make Internet Explorer’s ActiveX control look like the Mozilla built-in XMLHttpRequest. Both approaches are valid and can help to integrate legacy or third-party code (including the browsers themselves) into your Ajax project.
Licensed to jonathan zheng 80 CHAPTER 3 Introducing order to Ajax Calling code loadXML() function Implicit XMLHttpRequest interface Implicit XMLHttpRequest interface Native XMLHttpRequest ActiveX XMLHttpRequest Figure 3.1 Schematic of the Façade pattern, as it relates to the XMLHttpRequest object across browsers. The loadXML() function requires an XMLHttpRequest object, but doesn't care about its actual implementation. Underlying implementations may offer considerably more complex HTTP Request semantics, but both are simplified here to provide the basic functionality required by the calling function. Let’s move on to the next case study, in which we consider issues with JavaScript’s event-handling model. 3.2.2 Managing event handlers: Observer pattern We can’t write very much Ajax code without coming across event-based programming techniques. JavaScript user interfaces are heavily event-driven, and the introduction of asynchronous requests with Ajax adds a further set of callbacks and events for our application to deal with. In a relatively simple application, an event such as a mouse click or the arrival of data from the server can be handled by a single function. As an application grows in size and complexity, though, we may want to notify several distinct subsystems and even to expose a mechanism whereby interested parties can sign themselves up for such notification. Let’s explore an example to see what the issues are. Licensed to jonathan zheng Some small refactoring