Implementing 5 Common Design Patterns in JavaScript (ES8)

In this tutorial, we’ll see how common design patterns can be used as blueprints for organizing larger structures.

Defining steps with template functions

A template is a design pattern that details the order a given set of operations are to be executed in; however, a template does not outline the steps themselves. This pattern is useful when behavior is divided into phases that have some conceptual or side effect dependency that requires them to be executed in a specific order. Here, we’ll see how to use the template function design pattern.

We assume you already have a workspace that allows you to create and run ES modules in your browser for all the recipes given below:

How to do it…

Open your command-line application and navigate to your workspace.

Create a new folder named 09-01-defining-steps-with-template-functions.

Copy or create an index.html file that loads and runs a main function from main.js.

Create a main.js file that defines a new abstract class named Mission:

Start your Python web server and open the following link in your browser:http://localhost:8000/.

The output should appear as follows:

How it works…

The Mission abstract class defines the execute method, which calls the other instance methods in a particular order. You’ll notice that the methods called are not defined by the Mission class. This implementation detail is the responsibility of the extending classes. This use of abstract classes allows child classes to be used by code that takes advantage of the interface defined by the abstract class.

In the template function pattern, it is the responsibility of the child classes to define the steps. When they are instantiated, and the execute method is called, those steps are then performed in the specified order.

Ideally, we’d be able to ensure that Mission.execute was not overridden by any inheriting classes. Overriding this method works against the pattern and breaks the contract associated with it.

This pattern is useful for organizing data-processing pipelines. The guarantee that these steps will occur in a given order means that, if side effects are eliminated, the instances can be organized more flexibly. The implementing class can then organize these steps in the best possible way.

Assembling customized instances with builders

The previous recipe shows how to organize the operations of a class. Sometimes, object initialization can also be complicated. In these situations, it can be useful to take advantage of another design pattern: builders.

Now, we’ll see how to use builders to organize the initialization of more complicated objects.

How to do it…

Open your command-line application and navigate to your workspace.

Create a new folder named 09-02-assembling-instances-with-builders.

Create a main.js file that defines a new class named Mission, which that takes a name constructor argument and assigns it to an instance property. Also, create a describe method that prints out some details:

Start your Python web server and open the following link in your browser: http://localhost:8000/.

Your output should appear as follows:

How it works…

The builder defines methods for assigning all the relevant properties and defines a build method that ensures that each is called and assigned appropriately. Builders are like template functions, but instead of ensuring that a set of operations are executed in the correct order, they ensure that an instance is properly configured before returning.

Because each instance method of MissionBuilder returns the this reference, the methods can be chained. The last line of the main function calls describe on the new Mission instance that is returned from the build method.

Replicating instances with factories

Like builders, factories are a way of organizing object construction. They differ from builders in how they are organized. Often, the interface of factories is a single function call. This makes factories easier to use, if less customizable, than builders.

Now, we’ll see how to use factories to easily replicate instances.

How to do it…

Open your command-line application and navigate to your workspace.

Create a new folder named 09-03-replicating-instances-with-factories.

Copy or create an index.html that loads and runs a main function from main.js.

Create a main.js file that defines a new class named Mission. Add a constructor that takes a name constructor argument and assigns it to an instance property. Also, define a simple describe method:

Start your Python web server and open the following link in your browser:http://localhost:8000/.

Your output should appear as follows:

How it works…

The create method takes a subset of the properties needed to create a new mission. The remaining values are provided by the method itself. This allows factories to simplify the process of creating similar instances. In the main function, you can see that two Mars missions have been created, only differing in name and Rocket instance. We’ve halved the number of values needed to create an instance.

This pattern can help reduce instantiation logic. In this recipe, we simplified the creation of different kinds of missions by identifying the common attributes, encapsulating those in the body of the factory function, and using arguments to supply the remaining properties. In this way, commonly used instance shapes can be created without additional boilerplate code.

Processing a structure with the visitor pattern

The patterns we’ve seen thus far organize the construction of objects and the execution of operations. The next pattern we’ll look at is specially made to traverse and perform operations on hierarchical structures. Here, we’ll be looking at the visitor pattern.

How to do it…

Open your command-line application and navigate to your workspace.

Copy the 09-02-assembling-instances-with-builders folder to a new 09-04-processing-a-structure-with-the-visitor-pattern directory.

Add a class named MissionInspector to main.js. Create a visitor method that calls a corresponding method for each of the following types: Mission, Destination, Rocket, and Payload:

Start your Python web server and open the following link in your browser:http://localhost:8000/.

Your output should appear as follows:

How it works…

The visitor pattern has two components. The visitor processes the subject objects and the subjects tell other related subjects about the visitor, and when the current subject should be visited.

The accept method is required for each subject to receive a notification that there is a visitor. That method then makes two types of method call. The first is the accept method on its related subjects. The second is the visitor method on the visitor. In this way, the visitor traverses a structure by being passed around by the subjects.

The visitor methods are used to process different types of node. In some languages, this is handled by language-level polymorphism. In JavaScript, we can use run-time type checks to do this.

The visitor pattern is a good option for processing hierarchical structures of objects, where the structure is not known ahead of time, but the types of subjects are known.

Using a singleton to manage instances

Sometimes, there are objects that are resource intensive. They may require time, memory, battery power, or network usage that are unavailable or inconvenient. It is often useful to manage the creation and sharing of instances.

Here, we’ll see how to use singletons to manage instances.

How to do it…

Open your command-line application and navigate to your workspace.

Create a new folder named 09-05-singleton-to-manage-instances.

Copy or create an index.html that loads and runs a main function from main.js.

Create a main.js file that defines a new class named Rocket. Add a constructor takes a name constructor argument and assigns it to an instance property:

// main.js
class Rocket {
constructor (name) {
this.name = name;
}
}

Create a RocketManager object that has a rockets property. Add a findOrCreate method that indexes Rocket instances by the name property:

Start your Python web server and open the following link in your browser:http://localhost:8000/.

Your output should appear as follows:

How it works…

The object stores references to the instances, indexed by the string value given with name. This map is created when the module loads, so it is persisted through the life of the program. The singleton is then able to look up the object and returns instances created by findOrCreate with the same name.

Conserving resources and simplifying communication are primary motivations for using singletons. Creating a single object for multiple uses is more efficient in terms of space and time needed than creating several. Plus, having single instances for messages to be communicated through makes communication between different parts of a program easier.

Singletons may require more sophisticated indexing if they are relying on more complicated data.

You read an excerpt from a book written by Ross Harrison, titled ECMAScript Cookbook. This book contains over 70 recipes to help you improve your coding skills and solving practical JavaScript problems.