You are previewing Learning JavaScript Design Patterns.

Learning JavaScript Design Patterns

Cover of Learning JavaScript Design Patterns by Addy Osmani Published by O'Reilly Media, Inc.
  1. Learning JavaScript Design Patterns
  2. SPECIAL OFFER: Upgrade this ebook with O’Reilly
  3. Preface
    1. Target Audience
    2. Credits
    3. Reading
    4. Conventions Used in This Book
    5. Using Code Examples
    6. Safari® Books Online
    7. How to Contact Us
    8. Acknowledgments
  4. 1. Introduction
  5. 2. What Is a Pattern?
    1. We Already Use Patterns Every Day
  6. 3. “Pattern”-ity Testing, Proto-Patterns, and the Rule of Three
  7. 4. The Structure of a Design Pattern
  8. 5. Writing Design Patterns
  9. 6. Anti-Patterns
  10. 7. Categories of Design Patterns
    1. Creational Design Patterns
    2. Structural Design Patterns
    3. Behavioral Design Patterns
  11. 8. Design Pattern Categorization
    1. A Brief Note on Classes
  12. 9. JavaScript Design Patterns
    1. The Constructor Pattern
      1. Object Creation
      2. Basic Constructors
      3. Constructors with Prototypes
    2. The Module Pattern
      1. Object Literals
      2. The Module Pattern
      3. Module Pattern Variations
    3. The Revealing Module Pattern
      1. Advantages
      2. Disadvantages
    4. The Singleton Pattern
    5. The Observer Pattern
      1. Differences Between the Observer and Publish/Subscribe Pattern
      2. Advantages
      3. Disadvantages
      4. Publish/Subscribe Implementations
    6. The Mediator Pattern
      1. Basic Implementation
      2. Advanced Implementation
      3. Example
      4. Advantages and Disadvantages
      5. Mediator Versus Observer
      6. Mediator Versus Facade
    7. The Prototype Pattern
    8. The Command Pattern
    9. The Facade Pattern
      1. Notes on Abstraction
    10. The Factory Pattern
      1. When to Use the Factory Pattern
      2. When Not to Use the Factory Pattern
      3. Abstract Factories
    11. The Mixin Pattern
    12. Subclassing
    13. Mixins
      1. Advantages and Disadvantages
    14. The Decorator Pattern
    15. Pseudoclassical Decorators
      1. Interfaces
      2. Abstract Decorators
    16. Decorators with jQuery
    17. Advantages and Disadvantages
    18. Flyweight
      1. Using Flyweights
      2. Flyweights and Sharing Data
      3. Implementing Classical Flyweights
      4. Converting Code to Use the Flyweight Pattern
      5. A Basic Factory
      6. Managing the Extrinsic States
      7. The Flyweight Pattern and the DOM
  13. 10. JavaScript MV* Patterns
    1. MVC
      1. Smalltalk-80 MVC
    2. MVC for JavaScript Developers
      1. Models
      3. Controllers
      4. Controllers in Another Library (Spine.js) Versus Backbone.js
    3. What Does MVC Give Us?
    4. Smalltalk-80 MVC in JavaScript
      1. Delving Deeper
      2. Summary
    5. MVP
      1. Models, Views, and Presenters
      2. MVP or MVC?
      3. MVC, MVP, and Backbone.js
    6. MVVM
      1. History
      2. Model
      3. View
      4. ViewModel
      5. Recap: The View and the ViewModel
      6. Recap: The ViewModel and the Model
    7. Pros and Cons
      1. Advantages
      2. Disadvantages
    8. MVVM with Looser Data Bindings
    9. MVC Versus MVP Versus MVVM
    10. Backbone.js Versus KnockoutJS
  14. 11. Modern Modular JavaScript Design Patterns
    1. A Note on Script Loaders
    2. AMD
      1. Getting Started with Modules
      2. AMD Modules with Dojo
      3. AMD Module Design Patterns (Dojo)
      4. AMD Modules with jQuery
      5. AMD Conclusions
    3. CommonJS
      1. Getting Started
      2. Consuming Multiple Dependencies
      3. Loaders and Frameworks that Support CommonJS
      4. Is CommonJS Suitable for the Browser?
      5. Related Reading
    4. AMD and CommonJS: Competing, but Equally Valid Standards
      1. UMD: AMD and CommonJS-Compatible Modules for Plug-ins
    5. ES Harmony
      1. Modules with Imports and Exports
      2. Modules Loaded from Remote Sources
      3. Module Loader API
      4. CommonJS-like Modules for the Server
      5. Classes with Constructors, Getters, and Setters
      6. ES Harmony Conclusions
      7. Related Reading
    6. Conclusions
  15. 12. Design Patterns in jQuery
    1. The Composite Pattern
    2. The Adapter Pattern
    3. The Facade Pattern
    4. The Observer Pattern
    5. The Iterator Pattern
    6. Lazy Initialization
    7. The Proxy Pattern
    8. The Builder Pattern
  16. 13. jQuery Plug-in Design Patterns
    1. Patterns
    2. A Lightweight Start Pattern
      1. Further Reading
    3. Complete Widget Factory Pattern
      1. Further Reading
    4. Nested Namespacing Plug-in Pattern
      1. Further Reading
    5. Custom Events Plug-in Pattern (with the Widget Factory)
      1. Further Reading
    6. Prototypal Inheritance with the DOM-to-Object Bridge Pattern
      1. Further Reading
    7. jQuery UI Widget Factory Bridge Pattern
      1. Further Reading
    8. jQuery Mobile Widgets with the Widget Factory
    9. RequireJS and the jQuery UI Widget Factory
      1. Usage
      2. Further Reading
    10. Globally and Per-Call Overridable Options (Best Options Pattern)
      1. Further Reading
    11. A Highly Configurable and Mutable Plug-in Pattern
      1. Further Reading
    12. What Makes a Good Plug-in Beyond Patterns?
      1. Quality
      2. Code Style
      3. Compatibility
      4. Reliability
      5. Performance
      6. Documentation
      7. Likelihood of maintenance
    13. Conclusions
    14. Namespacing Patterns
    15. Namespacing Fundamentals
      1. Single Global Variables
      2. Prefix Namespacing
      3. Object Literal Notation
      4. Nested Namespacing
      5. Immediately Invoked Function Expressions (IIFE)s
      6. Namespace Injection
    16. Advanced Namespacing Patterns
      1. Automating Nested Namespacing
      2. Dependency Declaration Pattern
      3. Deep Object Extension
      4. Recommendation
  17. 14. Conclusions
  18. A. References
  19. Index
  20. About the Author
  21. Colophon
  22. SPECIAL OFFER: Upgrade this ebook with O’Reilly
  23. Copyright
O'Reilly logo

The Decorator Pattern

Decorators are a structural design pattern that aim to promote code reuse. Similar to Mixins, they can be considered another viable alternative to object subclassing.

Classically, Decorators offered the ability to add behavior to existing classes in a system dynamically. The idea was that the decoration itself wasn’t essential to the base functionality of the class; otherwise, it would be baked into the superclass itself.

They can be used to modify existing systems where we wish to add additional features to objects without the need to heavily modify the underlying code using them. A common reason why developers use them is that their applications may contain features requiring a large quantity of distinct types of object. Imagine having to define hundreds of different object constructors for, say, a JavaScript game (Figure 9-11).

Decorator pattern

Figure 9-11. Decorator pattern

The object constructors could represent distinct player types, each with differing capabilities. A Lord of the Rings game could require constructors for Hobbit, Elf, Orc, Wizard, Mountain Giant, Stone Giant, and so on, but there could easily be hundreds of these. If we then factored in capabilities, imagine having to create subclasses for each combination of capability type—e.g., HobbitWithRing, HobbitWithSword, HobbitWithRingAndSword, and so on. This isn’t very practical and certainly isn’t manageable when we factor in a growing number of different abilities.

The Decorator pattern isn’t heavily tied to how objects are created but instead focuses on the problem of extending their functionality. Rather than just relying on prototypal inheritance, we work with a single base object and progressively add decorator objects that provide the additional capabilities. The idea is that rather than subclassing, we add (decorate) properties or methods to a base object so it’s a little more streamlined.

Adding new attributes to objects in JavaScript is a very straightforward process, so with this in mind, a very simplistic decorator may be implemented as follows (Examples 9-7 and 9-8):

Example 9-7. Decorating Constructors with New Functionality

// A vehicle constructor
function vehicle( vehicleType ){

    // some sane defaults
    this.vehicleType = vehicleType || "car";
    this.model = "default";
    this.license = "00000-000";


// Test instance for a basic vehicle
var testInstance = new vehicle( "car" );
console.log( testInstance );

// Outputs:
// vehicle: car, model:default, license: 00000-000

// Lets create a new instance of vehicle, to be decorated
var truck = new vehicle( "truck" );

// New functionality we're decorating vehicle with
truck.setModel = function( modelName ){
    this.model = modelName;

truck.setColor = function( color ){
    this.color = color;
// Test the value setters and value assignment works correctly
truck.setModel( "CAT" );
truck.setColor( "blue" );

console.log( truck );

// Outputs:
// vehicle:truck, model:CAT, color: blue

// Demonstrate "vehicle" is still unaltered
var secondInstance = new vehicle( "car" );
console.log( secondInstance );

// Outputs:
// vehicle: car, model:default, license: 00000-000

This type of simplistic implementation is functional, but it doesn’t really demonstrate all of the strengths Decorators have to offer. For this, we’re first going to go through my variation of the Coffee example from an excellent book called Head First Design Patterns by Freeman, Sierra and Bates, which is modeled around a Macbook purchase.

Example 9-8. Decorating Objects with Multiple Decorators

// The constructor to decorate
function MacBook() { 

  this.cost = function () { return 997; }; 
  this.screenSize = function () { return 11.6; }; 


// Decorator 1
function Memory( macbook ) { 

  var v = macbook.cost(); 
  macbook.cost = function() { 
    return v + 75; 


// Decorator 2
function Engraving( macbook ){

  var v = macbook.cost(); 
  macbook.cost = function(){
    return  v + 200;

// Decorator 3
function Insurance( macbook ){

  var v = macbook.cost(); 
  macbook.cost = function(){
     return  v + 250;


var mb = new MacBook(); 
Memory( mb ); 
Engraving( mb );
Insurance( mb );

// Outputs: 1522
console.log( mb.cost() );

// Outputs: 11.6
console.log( mb.screenSize() );

In the example, our Decorators are overriding the MacBook() superclass object’s .cost() function to return the current price of the Macbook plus the cost of the upgrade being specified.

It’s considered a decoration’ as the original Macbook objects’ constructor methods that are not overridden (e.g. screenSize()), as well as any other properties that we may define as a part of the Macbook, remain unchanged and intact.

There isn’t really a defined interface in the previous example, and we’re shifting away the responsibility of ensuring an object meets an interface when moving from the creator to the receiver.

The best content for your career. Discover unlimited learning on demand for around $1/day.