Chapter 5. Behavioral Patterns
In the last chapter, we looked at structural patterns that describe ways in which objects can be constructed to ease interaction.
In this chapter, we'll take a look at the final, and largest, grouping of GoF patterns: behavioral patterns. These patterns are the ones that provide guidance on how objects share data, or from a different perspective, how data flows between objects.
The patterns we'll look at are:
- Chain of responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template method
- Visitor
Once again, there are a number of more recently identified patterns that could well be classified as behavioral patterns. We'll defer looking at those until a later chapter, instead keeping to the GoF patterns.
Chain of responsibility
We can think of a function call on an object as sending that object a message. Indeed this message-passing mentality was one that dates back to the days of Smalltalk. The chain of responsibility pattern describes an approach in which a message trickles down from one class to another. A class can either act on the message or allow it to be passed onto the next member of the chain. Depending on the implementation, there are a few different rules that can be applied to the message passing. In some situations, only the first matching link in the chain is permitted to act. In others, every matching link acts on the message. Sometimes, the links are permitted to stop processing or even to mutate the message as it continues down the chain. A typical message flow is shown in this diagram:
Let's see if we can find a good example of this pattern in our go to example land of Westeros.
Implementation
There is very little in the way of a legal system in Westeros. Certainly, there are laws and even city guards who enforce them but the judicial system is scant. The law of the land is really decided by the king and his advisors. Those with the time and money can petition for an audience with the king who will listen to their complaint and pass a ruling. This ruling is law. Of course, any king who spent his entire day listening to the complaints of peasants would go mad. For this reason, many of the cases are caught and solved by his advisors before they reach his ears.
To represent this in code, we'll need to start by thinking about how the chain of responsibility would work. A complaint comes in and it starts with the lowest possible person who can solve it. If that person cannot or will not solve the problem, it trickles up to a more senior member of the ruling class. Eventually, the problem reaches the king, who is the final arbiter of disputes. We can think of him as the default dispute solver who is called upon when all else fails. This is explained in the following diagram:
We'll start with an interface to describe those who might listen to complaints. Again, this is just pseudo code as there are no interfaces in JavaScript (all these interfaces are actually written in TypeScript, but that can be our little secret):
export interface ComplaintListener{ IsAbleToResolveComplaint(complaint: Complaint): boolean; ListenToComplaint(complaint: Complaint): string; }
The interface requires two methods. The first is a simple check to see if the class is able to resolve a given complaint. The second listens to and resolves the complaint. Next, we'll need to describe what constitutes a complaint. The following is the code of the Complaint
class:
var Complaint = (function () { function Complaint() { this.ComplainingParty = ""; this.ComplaintAbout = ""; this.Complaint = ""; } return Complaint; })();
Next, we need a couple of different classes that implement ComplaintListener
and are able to solve complaints:
var ClerkOfTheCourt = (function () { function ClerkOfTheCourt() { } ClerkOfTheCourt.prototype.IsAbleToResolveComplaint = function (complaint) { //decide if this is a complaint that can be solved by the clerk return false; }; ClerkOfTheCourt.prototype.ListenToComplaint = function (complaint) { //perform some operation //return solution to the complaint return ""; }; return ClerkOfTheCourt; })(); JudicialSystem.ClerkOfTheCourt = ClerkOfTheCourt; var King = (function () { function King() { } King.prototype.IsAbleToResolveComplaint = function (complaint) { return true; }; King.prototype.ListenToComplaint = function (complaint) { //perform some operation //return solution to the complaint return ""; }; return King; })(); JudicialSystem.King = King;
Each one of these classes implements a different approach to solving the complaint. We need to chain them together making sure that the King
class is in the default position. This can be seen in the following code:
var ComplaintResolver = (function () { function ComplaintResolver() { this.complaintListeners = new Array(); this.complaintListeners.push(new ClerkOfTheCourt()); this.complaintListeners.push(new King()); } ComplaintResolver.prototype.ResolveComplaint = function (complaint) { for (var i = 0; i < this.complaintListeners.length; i++) { if (this.complaintListeners[i].IsAbleToResolveComplaint(complaint)) { return this.complaintListeners[i].ListenToComplaint(complaint); } } }; return ComplaintResolver; })();
This code will work its way through each of the listeners until it finds one that is interested in hearing the complaint. In this version, the result is returned immediately, halting any further processing. There are variations of this pattern in which multiple listeners could fire, allowing the listeners to mutate the parameters for the next listener. A chain of listeners is shown here:
Chain of responsibility is a highly useful pattern in JavaScript. In browser-based JavaScript, the events that are fired fall through a chain of responsibility. For instance, you can attach multiple listeners to the click event on a link and each of them will fire until finally the default navigation listener fires. It is likely that you're using the chain of responsibility in most of your code without even knowing it.
Command
The command pattern is a method of encapsulating both the parameters to a method and the current object state, and the method to be called. In effect, the command pattern packs up everything needed to call a method at a later date into a nice little package. Using this approach, one can issue a command and wait until a later date to decide which piece of code will execute the command. This package can then be queued or even serialized for later execution. Having a single point of command execution also allows us to easily add functionality such as undo or command logging.
This pattern can be a bit difficult to imagine, so let's break it down into its components, as shown in the following diagram:
The command message
The first component of the command pattern is, predictably, the command itself. As I mentioned, the command encapsulates everything needed to invoke a method. This includes the method name, the parameters, and any global state. As you can imagine, keeping track of the global state in each command is very difficult. What happens if the global state changes after the command has been created? This dilemma is yet another reason why using a global state is problematic and should be avoided.
There are a couple of options to set up commands. At the simple end of the scale all that is needed is to track a function and a set of parameters. Because functions are first class objects in JavaScript, they can easily be saved into an object. We can also save the parameters to the function into a simple array. Let's build a command using this very simple approach.
The deferred nature of commands suggests an obvious metaphor in the land of Westeros. There are no methods of communicating quickly in Westeros. The best method is to attach small messages to birds and release them. The birds have a tendency to want to return to their homes so each lord raises a number of birds in their home and, when they come of age, sends them to other lords who might wish to communicate with them. The lords keep an aviary of birds and retain records of which bird will travel to which other lord. The king of Westeros sends many of his commands to his loyal lords through this method.
The commands sent by the king contain all the necessary instructions for the lords. The command may be something like "bring your troops" and the arguments to that command may be a number of troops, a location, and a date by which the command must be carried out.
In JavaScript, the simplest way of representing this is through an array:
var simpleCommand = new Array(); simpleCommand.push(new LordInstructions().BringTroops); simpleCommand.push("King's Landing"); simpleCommand.push(500); simpleCommand.push(new Date());
This array can be passed around and invoked at will. To invoke it, a generic function can be used, as shown in the following code:
simpleCommand[0](simpleCommand[1], simpleCommand[2], simpleCommand[3]);
As you can see, this function only works for commands with three arguments. You can, of course, expand this to any number:
simpleCommand[0](simpleCommand[1], simpleCommand[2], simpleCommand[3], simpleCommand[4], simpleCommand[5], simpleCommand[6]);
The additional parameters are undefined, but the function doesn't use them, so there is no ill effect. Of course, this is not at all an elegant solution.
It is desirable to build a class for each sort of command. This allows you to ensure the correct arguments have been supplied and easily distinguish the different sorts of commands in a collection. Typically, commands are named using the imperative, as they are instructions. Examples of this are BringTroops
, Surrender
, SendSupplies
, and so on.
Let's transform our ugly, simple command into a proper class:
var BringTroopsCommand = (function () { function BringTroopsCommand(location, numberOfTroops, when) { this._location = location; this._numberOfTroops = numberOfTroops; this._when = when; } BringTroopsCommand.prototype.Execute = function () { var receiver = new LordInstructions(); receiver.BringTroops(this._location, this._numberOfTroops, this._when); }; return BringTroopsCommand; })();
We may wish to implement some logic to ensure that the parameters passed into the constructor are correct. This will ensure that the command fails on creation instead of on execution. It is easier to debug the issue during creation rather than during execution as execution could be delayed, even for days. The validation won't be perfect, but even if it catches only a small portion of errors it is helpful.
As mentioned, these commands can be saved for later use in memory or even written to disk.
The invoker
The invoker is the part of the command pattern that instructs the command to execute its instructions. The invoker can really be anything; a timed event, a user interaction, or just the next step in the process may all trigger invocation. When we executed simpleCommand
earlier, we were playing at being the invoker. In the more rigorous command, the invoker might look something like:
command.Execute()
As you can see, invoking a command is very easy. Commands may be invoked at once or at some later date. One popular approach is to defer the execution of the command to the end of the event loop. This can be done in the node with:
process.nextTick(function(){command.Execute();});
The process.nextTick
function defers the execution of a command to the end of the event loop such that it is executed next time the process has nothing to do.
The receiver
The final component in the command pattern is the receiver. This is the target of the command execution. In our example, we created a receiver called LordInstructions
:
var LordInstructions = (function () { function LordInstructions() { } LordInstructions.prototype.BringTroops = function (location, numberOfTroops, when) { console.log("You have been instructed to bring " + numberOfTroops + " troops to " + location + " by " + when); }; return LordInstructions; })();
The receiver knows how to perform the action that the command has deferred. There need not be anything special about the receiver; in fact it may be any class.
Together these components make up the command pattern. A client will generate a command and pass it off to an invoker that may delay the command or execute it at once and the command will act upon a receiver.
In the case of building an undo stack, the commands are special, in that they have both an Execute
and an Undo
method. One takes the application state forward and the other backward. To perform an undo, simply pop the command off the undo stack, execute the Undo
function, and push it onto a redo stack. For redo, pop from redo, run Execute
, and push to the undo stack. Simple as that, although one must make sure all state mutations are performed through commands.
The GoF book outlines a slightly more complicated set of players for the command pattern. This is largely due to the reliance on interfaces that we've avoided in JavaScript. The pattern becomes much simpler thanks to the prototype inheritance model in JavaScript.
The command pattern is a very useful one to defer the execution of some piece of code. We'll actually explore the command pattern and some useful companion patterns in Chapter 9, Messaging Patterns.
The command message
The first component of the command pattern is, predictably, the command itself. As I mentioned, the command encapsulates everything needed to invoke a method. This includes the method name, the parameters, and any global state. As you can imagine, keeping track of the global state in each command is very difficult. What happens if the global state changes after the command has been created? This dilemma is yet another reason why using a global state is problematic and should be avoided.
There are a couple of options to set up commands. At the simple end of the scale all that is needed is to track a function and a set of parameters. Because functions are first class objects in JavaScript, they can easily be saved into an object. We can also save the parameters to the function into a simple array. Let's build a command using this very simple approach.
The deferred nature of commands suggests an obvious metaphor in the land of Westeros. There are no methods of communicating quickly in Westeros. The best method is to attach small messages to birds and release them. The birds have a tendency to want to return to their homes so each lord raises a number of birds in their home and, when they come of age, sends them to other lords who might wish to communicate with them. The lords keep an aviary of birds and retain records of which bird will travel to which other lord. The king of Westeros sends many of his commands to his loyal lords through this method.
The commands sent by the king contain all the necessary instructions for the lords. The command may be something like "bring your troops" and the arguments to that command may be a number of troops, a location, and a date by which the command must be carried out.
In JavaScript, the simplest way of representing this is through an array:
var simpleCommand = new Array(); simpleCommand.push(new LordInstructions().BringTroops); simpleCommand.push("King's Landing"); simpleCommand.push(500); simpleCommand.push(new Date());
This array can be passed around and invoked at will. To invoke it, a generic function can be used, as shown in the following code:
simpleCommand[0](simpleCommand[1], simpleCommand[2], simpleCommand[3]);
As you can see, this function only works for commands with three arguments. You can, of course, expand this to any number:
simpleCommand[0](simpleCommand[1], simpleCommand[2], simpleCommand[3], simpleCommand[4], simpleCommand[5], simpleCommand[6]);
The additional parameters are undefined, but the function doesn't use them, so there is no ill effect. Of course, this is not at all an elegant solution.
It is desirable to build a class for each sort of command. This allows you to ensure the correct arguments have been supplied and easily distinguish the different sorts of commands in a collection. Typically, commands are named using the imperative, as they are instructions. Examples of this are BringTroops
, Surrender
, SendSupplies
, and so on.
Let's transform our ugly, simple command into a proper class:
var BringTroopsCommand = (function () { function BringTroopsCommand(location, numberOfTroops, when) { this._location = location; this._numberOfTroops = numberOfTroops; this._when = when; } BringTroopsCommand.prototype.Execute = function () { var receiver = new LordInstructions(); receiver.BringTroops(this._location, this._numberOfTroops, this._when); }; return BringTroopsCommand; })();
We may wish to implement some logic to ensure that the parameters passed into the constructor are correct. This will ensure that the command fails on creation instead of on execution. It is easier to debug the issue during creation rather than during execution as execution could be delayed, even for days. The validation won't be perfect, but even if it catches only a small portion of errors it is helpful.
As mentioned, these commands can be saved for later use in memory or even written to disk.
The invoker
The invoker is the part of the command pattern that instructs the command to execute its instructions. The invoker can really be anything; a timed event, a user interaction, or just the next step in the process may all trigger invocation. When we executed simpleCommand
earlier, we were playing at being the invoker. In the more rigorous command, the invoker might look something like:
command.Execute()
As you can see, invoking a command is very easy. Commands may be invoked at once or at some later date. One popular approach is to defer the execution of the command to the end of the event loop. This can be done in the node with:
process.nextTick(function(){command.Execute();});
The process.nextTick
function defers the execution of a command to the end of the event loop such that it is executed next time the process has nothing to do.
The receiver
The final component in the command pattern is the receiver. This is the target of the command execution. In our example, we created a receiver called LordInstructions
:
var LordInstructions = (function () { function LordInstructions() { } LordInstructions.prototype.BringTroops = function (location, numberOfTroops, when) { console.log("You have been instructed to bring " + numberOfTroops + " troops to " + location + " by " + when); }; return LordInstructions; })();
The receiver knows how to perform the action that the command has deferred. There need not be anything special about the receiver; in fact it may be any class.
Together these components make up the command pattern. A client will generate a command and pass it off to an invoker that may delay the command or execute it at once and the command will act upon a receiver.
In the case of building an undo stack, the commands are special, in that they have both an Execute
and an Undo
method. One takes the application state forward and the other backward. To perform an undo, simply pop the command off the undo stack, execute the Undo
function, and push it onto a redo stack. For redo, pop from redo, run Execute
, and push to the undo stack. Simple as that, although one must make sure all state mutations are performed through commands.
The GoF book outlines a slightly more complicated set of players for the command pattern. This is largely due to the reliance on interfaces that we've avoided in JavaScript. The pattern becomes much simpler thanks to the prototype inheritance model in JavaScript.
The command pattern is a very useful one to defer the execution of some piece of code. We'll actually explore the command pattern and some useful companion patterns in Chapter 9, Messaging Patterns.
The invoker
The invoker is the part of the command pattern that instructs the command to execute its instructions. The invoker can really be anything; a timed event, a user interaction, or just the next step in the process may all trigger invocation. When we executed simpleCommand
earlier, we were playing at being the invoker. In the more rigorous command, the invoker might look something like:
command.Execute()
As you can see, invoking a command is very easy. Commands may be invoked at once or at some later date. One popular approach is to defer the execution of the command to the end of the event loop. This can be done in the node with:
process.nextTick(function(){command.Execute();});
The process.nextTick
function defers the execution of a command to the end of the event loop such that it is executed next time the process has nothing to do.
The receiver
The final component in the command pattern is the receiver. This is the target of the command execution. In our example, we created a receiver called LordInstructions
:
var LordInstructions = (function () { function LordInstructions() { } LordInstructions.prototype.BringTroops = function (location, numberOfTroops, when) { console.log("You have been instructed to bring " + numberOfTroops + " troops to " + location + " by " + when); }; return LordInstructions; })();
The receiver knows how to perform the action that the command has deferred. There need not be anything special about the receiver; in fact it may be any class.
Together these components make up the command pattern. A client will generate a command and pass it off to an invoker that may delay the command or execute it at once and the command will act upon a receiver.
In the case of building an undo stack, the commands are special, in that they have both an Execute
and an Undo
method. One takes the application state forward and the other backward. To perform an undo, simply pop the command off the undo stack, execute the Undo
function, and push it onto a redo stack. For redo, pop from redo, run Execute
, and push to the undo stack. Simple as that, although one must make sure all state mutations are performed through commands.
The GoF book outlines a slightly more complicated set of players for the command pattern. This is largely due to the reliance on interfaces that we've avoided in JavaScript. The pattern becomes much simpler thanks to the prototype inheritance model in JavaScript.
The command pattern is a very useful one to defer the execution of some piece of code. We'll actually explore the command pattern and some useful companion patterns in Chapter 9, Messaging Patterns.
The receiver
The final component in the command pattern is the receiver. This is the target of the command execution. In our example, we created a receiver called LordInstructions
:
var LordInstructions = (function () { function LordInstructions() { } LordInstructions.prototype.BringTroops = function (location, numberOfTroops, when) { console.log("You have been instructed to bring " + numberOfTroops + " troops to " + location + " by " + when); }; return LordInstructions; })();
The receiver knows how to perform the action that the command has deferred. There need not be anything special about the receiver; in fact it may be any class.
Together these components make up the command pattern. A client will generate a command and pass it off to an invoker that may delay the command or execute it at once and the command will act upon a receiver.
In the case of building an undo stack, the commands are special, in that they have both an Execute
and an Undo
method. One takes the application state forward and the other backward. To perform an undo, simply pop the command off the undo stack, execute the Undo
function, and push it onto a redo stack. For redo, pop from redo, run Execute
, and push to the undo stack. Simple as that, although one must make sure all state mutations are performed through commands.
The GoF book outlines a slightly more complicated set of players for the command pattern. This is largely due to the reliance on interfaces that we've avoided in JavaScript. The pattern becomes much simpler thanks to the prototype inheritance model in JavaScript.
The command pattern is a very useful one to defer the execution of some piece of code. We'll actually explore the command pattern and some useful companion patterns in Chapter 9, Messaging Patterns.
Interpreter
The interpreter pattern is an interesting pattern as it allows for the creation of your own language. This might sound like a crazy idea: we're already writing JavaScript, why would we want to create a new language? Since the publication of the GoF book, domain specific languages (DSLs) have had something of a renaissance. There are situations where it is quite useful to create a language that is specific to one requirement. For instance, Structured Query Language (SQL) is very good at describing the querying of relational databases. Equally, regular expressions have proven themselves to be highly effective for the parsing and manipulation of text.
There are many scenarios in which being able to create a simple language is useful. That's really the key: a simple language. Once the language gets more complicated, the advantages are quickly lost to the difficulty of creating what is, in effect, a compiler.
This pattern is different from those we've seen to this point as there is no real class structure that is defined by the pattern. You can design your language interpreter as you wish.
An example
For our example, let's define a language that can be used to describe historical battles in the land of Westeros. The language must be simple for clerics to write and easy to read. We'll start by creating a simple grammar such as (aggressor -> battle ground <- defender) -> victor
.
In the preceding line, you can see that we're just writing out a rather nice syntax that will let people describe battles. A battle between Robert Baratheon and Rhaegar Targaryen at the river Trident would look like (Robert Baratheon -> River Trident <- RhaegarTargaryen) -> Robert Baratheon
.
Using this grammar, we would like to build some code that is able to query a list of battles for answers. In order to do this, we're going to rely on regular expressions. For most languages, this wouldn't be a good approach as the grammar is too complicated. In those cases, one might wish to create a lexor and a parser and build up syntax trees; however, by that point, you may wish to reexamine whether creating a DSL is really a good idea. For our language, the syntax is very simple, so we can get away with regular expressions.
Implementation
The first thing we establish is a JavaScript data model for the battle as follows:
var Battle = (function () { function Battle(battleGround, agressor, defender, victor) { this.battleGround = battleGround; this.agressor = agressor; this.defender = defender; this.victor = victor; } return Battle; })();
Next, we need a parser:
var Parser = (function () { function Parser(battleText) { this.battleText = battleText; this.currentIndex = 0; this.battleList = battleText.split("\n"); } Parser.prototype.nextBattle = function () { if (!this.battleList[0]) return null; var segments = this.battleList[0].match(/\((.+?)\s?->\s?(.+?)\s?<-\s?(.+?)\s?->\s?(.+)/); return new Battle(segments[2], segments[1], segments[3], segments[4]); }; return Parser; })();
It is likely best that you don't think too much about that regular expression. However, the class does take in a list of battles (one per line) and using nextBattle
allows one to parse them. To use the class, we simply need the following code:
var text = "(Robert Baratheon -> River Trident <- RhaegarTargaryen) -> Robert Baratheon"; var p = new Parser(text); p.nextBattle()
Its output will be:
{ battleGround: 'River Trident', agressor: 'Robert Baratheon', defender: 'RhaegarTargaryen)', victor: 'Robert Baratheon' }
This data structure can now be queried like one would for any other structure in JavaScript.
As I mentioned earlier, there is no fixed way to implement this pattern, so the previous implementation is provided simply as an example. Your implementation will very likely look very different and that is just fine.
Interpreter can be a useful pattern in JavaScript. It is, however, a pretty infrequently used pattern in most situations. The best example of a language interpreted in JavaScript is the Less language that is compiled, by JavaScript, to CSS.
An example
For our example, let's define a language that can be used to describe historical battles in the land of Westeros. The language must be simple for clerics to write and easy to read. We'll start by creating a simple grammar such as (aggressor -> battle ground <- defender) -> victor
.
In the preceding line, you can see that we're just writing out a rather nice syntax that will let people describe battles. A battle between Robert Baratheon and Rhaegar Targaryen at the river Trident would look like (Robert Baratheon -> River Trident <- RhaegarTargaryen) -> Robert Baratheon
.
Using this grammar, we would like to build some code that is able to query a list of battles for answers. In order to do this, we're going to rely on regular expressions. For most languages, this wouldn't be a good approach as the grammar is too complicated. In those cases, one might wish to create a lexor and a parser and build up syntax trees; however, by that point, you may wish to reexamine whether creating a DSL is really a good idea. For our language, the syntax is very simple, so we can get away with regular expressions.
Implementation
The first thing we establish is a JavaScript data model for the battle as follows:
var Battle = (function () { function Battle(battleGround, agressor, defender, victor) { this.battleGround = battleGround; this.agressor = agressor; this.defender = defender; this.victor = victor; } return Battle; })();
Next, we need a parser:
var Parser = (function () { function Parser(battleText) { this.battleText = battleText; this.currentIndex = 0; this.battleList = battleText.split("\n"); } Parser.prototype.nextBattle = function () { if (!this.battleList[0]) return null; var segments = this.battleList[0].match(/\((.+?)\s?->\s?(.+?)\s?<-\s?(.+?)\s?->\s?(.+)/); return new Battle(segments[2], segments[1], segments[3], segments[4]); }; return Parser; })();
It is likely best that you don't think too much about that regular expression. However, the class does take in a list of battles (one per line) and using nextBattle
allows one to parse them. To use the class, we simply need the following code:
var text = "(Robert Baratheon -> River Trident <- RhaegarTargaryen) -> Robert Baratheon"; var p = new Parser(text); p.nextBattle()
Its output will be:
{ battleGround: 'River Trident', agressor: 'Robert Baratheon', defender: 'RhaegarTargaryen)', victor: 'Robert Baratheon' }
This data structure can now be queried like one would for any other structure in JavaScript.
As I mentioned earlier, there is no fixed way to implement this pattern, so the previous implementation is provided simply as an example. Your implementation will very likely look very different and that is just fine.
Interpreter can be a useful pattern in JavaScript. It is, however, a pretty infrequently used pattern in most situations. The best example of a language interpreted in JavaScript is the Less language that is compiled, by JavaScript, to CSS.
Implementation
The first thing we establish is a JavaScript data model for the battle as follows:
var Battle = (function () { function Battle(battleGround, agressor, defender, victor) { this.battleGround = battleGround; this.agressor = agressor; this.defender = defender; this.victor = victor; } return Battle; })();
Next, we need a parser:
var Parser = (function () { function Parser(battleText) { this.battleText = battleText; this.currentIndex = 0; this.battleList = battleText.split("\n"); } Parser.prototype.nextBattle = function () { if (!this.battleList[0]) return null; var segments = this.battleList[0].match(/\((.+?)\s?->\s?(.+?)\s?<-\s?(.+?)\s?->\s?(.+)/); return new Battle(segments[2], segments[1], segments[3], segments[4]); }; return Parser; })();
It is likely best that you don't think too much about that regular expression. However, the class does take in a list of battles (one per line) and using nextBattle
allows one to parse them. To use the class, we simply need the following code:
var text = "(Robert Baratheon -> River Trident <- RhaegarTargaryen) -> Robert Baratheon"; var p = new Parser(text); p.nextBattle()
Its output will be:
{ battleGround: 'River Trident', agressor: 'Robert Baratheon', defender: 'RhaegarTargaryen)', victor: 'Robert Baratheon' }
This data structure can now be queried like one would for any other structure in JavaScript.
As I mentioned earlier, there is no fixed way to implement this pattern, so the previous implementation is provided simply as an example. Your implementation will very likely look very different and that is just fine.
Interpreter can be a useful pattern in JavaScript. It is, however, a pretty infrequently used pattern in most situations. The best example of a language interpreted in JavaScript is the Less language that is compiled, by JavaScript, to CSS.
Iterator
Traversing collections of objects is an amazingly common problem, so much so that many languages provide for special constructs just to move through collections. For example, C# has a foreach
loop and Python has for x in
. These looping constructs are frequently built on top of an iterator. An iterator is a pattern that provides a simple method to select, sequentially, the next item in a collection.
The interface for the iterator looks like the following code:
interface Iterator{ next(); }
Implementation
In the land of Westeros, there is a well-known sequence of people in line for the throne in the very unlikely event that the king were to die. We can set up a handy iterator on top of this collection and simply call next
on it should the ruler die. The following code keeps track of a pointer to the current element in the iteration:
var KingSuccession = (function () { function KingSuccession(inLineForThrone) { this.inLineForThrone = inLineForThrone; this.pointer = 0; } KingSuccession.prototype.next = function () { return this.inLineForThrone[this.pointer++]; }; return KingSuccession; })();
This is primed with an array and then we can call it with the following code:
var king = new KingSuccession(["Robert Baratheon" ,"JofferyBaratheon", "TommenBaratheon"]); king.next() //'Robert Baratheon' king.next() //'JofferyBaratheon' king.next() //'TommenBaratheon'
An interesting application of iterators is to iterate over a collection that is not fixed. For instance, an iterator can be used to generate sequential members of an infinite set like the Fibonacci sequence:
var FibonacciIterator = (function () { function FibonacciIterator() { this.previous = 1; this.beforePrevious = 1; } FibonacciIterator.prototype.next = function () { var current = this.previous + this.beforePrevious; this.beforePrevious = this.previous; this.previous = current; return current; }; return FibonacciIterator; })();
This is used as follows:
var fib = new FibonacciIterator() fib.next() //2 fib.next() //3 fib.next() //5 fib.next() //8 fib.next() //13 fib.next() //21
Iterators are handy constructs allowing to explore not just arrays but any collection or even any generated list. There are a ton of places where this can be used to great effect.
ECMAScript 6 iterators
Iterators are so useful that they are actually part of the next generation of JavaScript. The iterator pattern used in ECMAScript 6 is a single method that returns an object that contains a done
and
value
parameters. The done
parameter is true
when the iterator is at the end of the collection. What is nice about the ECMAScript 6 iterators is that the array collection in JavaScript will support the iterator. This opens up a new syntax that can largely replace the for
loop:
var kings = new KingSuccession(["Robert Baratheon" ,"JofferyBaratheon", "TommenBaratheon"]); for(var king of kings){ //act on members of kings }
Iterators are a syntactic nicety that has long been missing from JavaScript.
Implementation
In the land of Westeros, there is a well-known sequence of people in line for the throne in the very unlikely event that the king were to die. We can set up a handy iterator on top of this collection and simply call next
on it should the ruler die. The following code keeps track of a pointer to the current element in the iteration:
var KingSuccession = (function () { function KingSuccession(inLineForThrone) { this.inLineForThrone = inLineForThrone; this.pointer = 0; } KingSuccession.prototype.next = function () { return this.inLineForThrone[this.pointer++]; }; return KingSuccession; })();
This is primed with an array and then we can call it with the following code:
var king = new KingSuccession(["Robert Baratheon" ,"JofferyBaratheon", "TommenBaratheon"]); king.next() //'Robert Baratheon' king.next() //'JofferyBaratheon' king.next() //'TommenBaratheon'
An interesting application of iterators is to iterate over a collection that is not fixed. For instance, an iterator can be used to generate sequential members of an infinite set like the Fibonacci sequence:
var FibonacciIterator = (function () { function FibonacciIterator() { this.previous = 1; this.beforePrevious = 1; } FibonacciIterator.prototype.next = function () { var current = this.previous + this.beforePrevious; this.beforePrevious = this.previous; this.previous = current; return current; }; return FibonacciIterator; })();
This is used as follows:
var fib = new FibonacciIterator() fib.next() //2 fib.next() //3 fib.next() //5 fib.next() //8 fib.next() //13 fib.next() //21
Iterators are handy constructs allowing to explore not just arrays but any collection or even any generated list. There are a ton of places where this can be used to great effect.
ECMAScript 6 iterators
Iterators are so useful that they are actually part of the next generation of JavaScript. The iterator pattern used in ECMAScript 6 is a single method that returns an object that contains a done
and
value
parameters. The done
parameter is true
when the iterator is at the end of the collection. What is nice about the ECMAScript 6 iterators is that the array collection in JavaScript will support the iterator. This opens up a new syntax that can largely replace the for
loop:
var kings = new KingSuccession(["Robert Baratheon" ,"JofferyBaratheon", "TommenBaratheon"]); for(var king of kings){ //act on members of kings }
Iterators are a syntactic nicety that has long been missing from JavaScript.
ECMAScript 6 iterators
Iterators are so useful that they are actually part of the next generation of JavaScript. The iterator pattern used in ECMAScript 6 is a single method that returns an object that contains a done
and
value
parameters. The done
parameter is true
when the iterator is at the end of the collection. What is nice about the ECMAScript 6 iterators is that the array collection in JavaScript will support the iterator. This opens up a new syntax that can largely replace the for
loop:
var kings = new KingSuccession(["Robert Baratheon" ,"JofferyBaratheon", "TommenBaratheon"]); for(var king of kings){ //act on members of kings }
Iterators are a syntactic nicety that has long been missing from JavaScript.
Mediator
Managing many-to-many relationships in classes can be a complicated prospect. Let's consider a form that contains a number of controls, each of which wants to know if other controls on the page are valid before performing their action. Unfortunately, having each control know about every other control creates a maintenance nightmare. Each time a new control is added every other control needs to be modified.
A mediator will sit between the various components and act as a single place in which message routing changes can be made. By doing so, the mediator simplifies the otherwise complex work needed to maintain the code. In the case of controls on a form, the mediator is likely to be the form itself. The mediator acts much like a real-life mediator would, clarifying and routing information exchange between a number of parties. The following diagram illustrates the mediator pattern:
Implementation
In the land of Westeros, there are many times when a mediator is needed. Frequently, the mediator ends up deceased, but I'm sure that won't be the case with our example.
There are a number of great families in Westeros who own large castles and vast tracts of land. Lesser lords swear themselves to the great houses, forming alliances, frequently supported through marriage.
When coordinating the various houses sworn to them, the great lord will act as a mediator, communicating information back and forth between the lesser lords and resolving any disputes they may have amongst themselves.
In this example, we'll greatly simplify the communication between the houses and say that all messages pass through the great lord. In this case, we'll use the house of Stark as our great lord. They have a number of other houses which talk with them. Each of the houses looks roughly like:
var Karstark = (function () { function Karstark(greatLord) { this.greatLord = greatLord; } Karstark.prototype.receiveMessage = function (message) { }; Karstark.prototype.sendMessage = function (message) { this.greatLord.routeMessage(message); }; return Karstark; })();
They have two functions, one of which receives messages from a third party and one of which sends messages out to their great lord that is set upon instantiation. The HouseStark
class looks like the following code:
var HouseStark = (function () { function HouseStark() { this.karstark = new Karstark(this); this.bolton = new Bolton(this); this.frey = new Frey(this); this.umber = new Umber(this); } HouseStark.prototype.routeMessage = function (message) { }; return HouseStark; })();
By passing all messages through the HouseStark
class, the various other houses do not need to concern themselves with how their messages are routed. This responsibility is handed off to HouseStark
, which acts as the mediator.
Mediators are best used when the communication is both complex and well defined. If the communication is not complex, then the mediator adds extra complexity. If the communication is ill defined, then it becomes difficult to codify the communication rules in a single place.
Simplifying communication between many-to-many objects is certainly useful in JavaScript. I would actually argue that in many ways jQuery acts as a mediator. When acting on a set of items on the page, jQuery serves to simplify communication by abstracting away the need to know exactly which objects on the page are being changed. For instance, refer to the following code:
$(".error").slideToggle();
This is jQuery shorthand to toggle the visibility of all the elements on the page that have the error
class.
Implementation
In the land of Westeros, there are many times when a mediator is needed. Frequently, the mediator ends up deceased, but I'm sure that won't be the case with our example.
There are a number of great families in Westeros who own large castles and vast tracts of land. Lesser lords swear themselves to the great houses, forming alliances, frequently supported through marriage.
When coordinating the various houses sworn to them, the great lord will act as a mediator, communicating information back and forth between the lesser lords and resolving any disputes they may have amongst themselves.
In this example, we'll greatly simplify the communication between the houses and say that all messages pass through the great lord. In this case, we'll use the house of Stark as our great lord. They have a number of other houses which talk with them. Each of the houses looks roughly like:
var Karstark = (function () { function Karstark(greatLord) { this.greatLord = greatLord; } Karstark.prototype.receiveMessage = function (message) { }; Karstark.prototype.sendMessage = function (message) { this.greatLord.routeMessage(message); }; return Karstark; })();
They have two functions, one of which receives messages from a third party and one of which sends messages out to their great lord that is set upon instantiation. The HouseStark
class looks like the following code:
var HouseStark = (function () { function HouseStark() { this.karstark = new Karstark(this); this.bolton = new Bolton(this); this.frey = new Frey(this); this.umber = new Umber(this); } HouseStark.prototype.routeMessage = function (message) { }; return HouseStark; })();
By passing all messages through the HouseStark
class, the various other houses do not need to concern themselves with how their messages are routed. This responsibility is handed off to HouseStark
, which acts as the mediator.
Mediators are best used when the communication is both complex and well defined. If the communication is not complex, then the mediator adds extra complexity. If the communication is ill defined, then it becomes difficult to codify the communication rules in a single place.
Simplifying communication between many-to-many objects is certainly useful in JavaScript. I would actually argue that in many ways jQuery acts as a mediator. When acting on a set of items on the page, jQuery serves to simplify communication by abstracting away the need to know exactly which objects on the page are being changed. For instance, refer to the following code:
$(".error").slideToggle();
This is jQuery shorthand to toggle the visibility of all the elements on the page that have the error
class.
Memento
In the Command section, we talked briefly about the ability to undo operations. Creating reversible commands is not always possible. For many operations, there is no apparent reversing operation that can restore the original state. For instance, imagine the code that squares a number:
var SquareCommand = (function () { function SquareCommand(numberToSquare) { this.numberToSquare = numberToSquare; } SquareCommand.prototype.Execute = function () { this.numberToSquare *= this.numberToSquare; }; return SquareCommand; })();
Giving this code, -9 will result in 81 but giving it 9 will also result in 81. There is no way to reverse this command without additional information.
The memento pattern provides an approach to restore the state of objects to a previous state. The memento keeps a record of the previous values of a variable and provides the functionality to restore them. Keeping a memento around for each command allows for easy restoration of irreversible commands.
In addition to an undo-stack, there are many instances where having the ability to roll back the state of an object is useful. For instance, doing "what-if" analysis requires that you make some hypothetical changes to a state and then observe how things change. The changes are generally not permanent so they could be rolled back using the memento pattern or, if the projects are desirable, left in place. The following diagram explains a typical memento implementation:
A typical memento implementation involves three players:
- Originator: The originator holds some form of the state and provides an interface to generate new mementos.
- Caretaker: This is the client of the pattern. It is what requests that new mementos be taken and governs when they are to be restored.
- Memento: This is a representation of the saved state of the originator. This is what can be saved to storage to allow for rolling back.
It can help to think of the members of the memento pattern as a boss and a secretary taking notes. The boss (caretaker) dictates some memo to the secretary (originator) who writes notes in a notepad (memento). From time to time, the boss may request that the secretary cross out what he has just written.
The involvement of the caretaker can be varied slightly with the memento pattern. In some implementation, the originator will generate a new memento each time a change is made to its state. This is commonly known as copy on write, as a new copy of the state is created and the change is applied to it. The old version can be saved to a memento.
Implementation
In the land of Westeros, there are a number of soothsayers/foretellers of the future. They work by using magic to peer into the future and examining how certain changes in the present will play out in the future. Often, there is need for numerous foretellings with slightly different starting conditions. When setting their starting conditions, a memento pattern is invaluable.
We start off with a world state that gives information on the state of the world for a certain starting point:
var WorldState = (function () { function WorldState(numberOfKings, currentKingInKingsLanding, season) { this.numberOfKings = numberOfKings; this.currentKingInKingsLanding = currentKingInKingsLanding; this.season = season; } return WorldState; })();
This world state is used to track all the conditions that make up the world. It is what is altered by the application every time a change to the starting conditions is made. Because this world state encompasses the whole state for the application, it can be used as a memento. We can serialize this object and save it to the disk or send it back to some history server somewhere.
The next thing we need is a class that provides the same state as the memento and allows for the creation and restoration of mementos. In our example, we've called this a world state provider:
var WorldStateProvider = (function () { function WorldStateProvider() { } WorldStateProvider.prototype.saveMemento = function () { return new WorldState(this.numberOfKings, this.currentKingInKingsLanding, this.season); }; WorldStateProvider.prototype.restoreMemento = function (memento) { this.numberOfKings = memento.numberOfKings; this.currentKingInKingsLanding = memento.currentKingInKingsLanding; this.season = memento.season; }; return WorldStateProvider; })();
Finally, we need a client for the foretelling, which we'll call soothsayer:
var Soothsayer = (function () { function Soothsayer() { this.startingPoints = []; this.currentState = new WorldStateProvider(); } Soothsayer.prototype.setInitialConditions = function (numberOfKings, currentKingInKingsLanding, season) { this.currentState.numberOfKings = numberOfKings; this.currentState.currentKingInKingsLanding = currentKingInKingsLanding; this.currentState.season = season; }; Soothsayer.prototype.alterNumberOfKingsAndForetell = function (numberOfKings) { this.startingPoints.push(this.currentState.saveMemento()); this.currentState.numberOfKings = numberOfKings; //run some sort of prediction }; Soothsayer.prototype.alterSeasonAndForetell = function (season) { //as above }; Soothsayer.prototype.alterCurrentKingInKingsLandingAndForetell = function (currentKingInKingsLanding) { //as above }; Soothsayer.prototype.tryADifferentChange = function () { this.currentState.restoreMemento(this.startingPoints.pop()); }; return Soothsayer; })();
This class provides a number of convenient methods that alter the state of the world and then run a foretelling. Each of these methods pushes the previous state into the history array, startingPoints
. There is also a method, tryADifferentChange
, which undoes the previous state change and gets ready to run another foretelling. The undo is performed by loading back the memento that is stored in an array.
Despite a great pedigree, it is very rare that client-side JavaScript applications provide an undo function. I'm sure there are various reasons for this, but for the most part it is likely that people do not expect such functionality. However, in most desktop applications, having an undo function is expected. I imagine that as a client-side application continues to grow in its capabilities, the undo functionality will become more important. When it does, the memento pattern is a fantastic way of implementing the undo stack.
Implementation
In the land of Westeros, there are a number of soothsayers/foretellers of the future. They work by using magic to peer into the future and examining how certain changes in the present will play out in the future. Often, there is need for numerous foretellings with slightly different starting conditions. When setting their starting conditions, a memento pattern is invaluable.
We start off with a world state that gives information on the state of the world for a certain starting point:
var WorldState = (function () { function WorldState(numberOfKings, currentKingInKingsLanding, season) { this.numberOfKings = numberOfKings; this.currentKingInKingsLanding = currentKingInKingsLanding; this.season = season; } return WorldState; })();
This world state is used to track all the conditions that make up the world. It is what is altered by the application every time a change to the starting conditions is made. Because this world state encompasses the whole state for the application, it can be used as a memento. We can serialize this object and save it to the disk or send it back to some history server somewhere.
The next thing we need is a class that provides the same state as the memento and allows for the creation and restoration of mementos. In our example, we've called this a world state provider:
var WorldStateProvider = (function () { function WorldStateProvider() { } WorldStateProvider.prototype.saveMemento = function () { return new WorldState(this.numberOfKings, this.currentKingInKingsLanding, this.season); }; WorldStateProvider.prototype.restoreMemento = function (memento) { this.numberOfKings = memento.numberOfKings; this.currentKingInKingsLanding = memento.currentKingInKingsLanding; this.season = memento.season; }; return WorldStateProvider; })();
Finally, we need a client for the foretelling, which we'll call soothsayer:
var Soothsayer = (function () { function Soothsayer() { this.startingPoints = []; this.currentState = new WorldStateProvider(); } Soothsayer.prototype.setInitialConditions = function (numberOfKings, currentKingInKingsLanding, season) { this.currentState.numberOfKings = numberOfKings; this.currentState.currentKingInKingsLanding = currentKingInKingsLanding; this.currentState.season = season; }; Soothsayer.prototype.alterNumberOfKingsAndForetell = function (numberOfKings) { this.startingPoints.push(this.currentState.saveMemento()); this.currentState.numberOfKings = numberOfKings; //run some sort of prediction }; Soothsayer.prototype.alterSeasonAndForetell = function (season) { //as above }; Soothsayer.prototype.alterCurrentKingInKingsLandingAndForetell = function (currentKingInKingsLanding) { //as above }; Soothsayer.prototype.tryADifferentChange = function () { this.currentState.restoreMemento(this.startingPoints.pop()); }; return Soothsayer; })();
This class provides a number of convenient methods that alter the state of the world and then run a foretelling. Each of these methods pushes the previous state into the history array, startingPoints
. There is also a method, tryADifferentChange
, which undoes the previous state change and gets ready to run another foretelling. The undo is performed by loading back the memento that is stored in an array.
Despite a great pedigree, it is very rare that client-side JavaScript applications provide an undo function. I'm sure there are various reasons for this, but for the most part it is likely that people do not expect such functionality. However, in most desktop applications, having an undo function is expected. I imagine that as a client-side application continues to grow in its capabilities, the undo functionality will become more important. When it does, the memento pattern is a fantastic way of implementing the undo stack.
Observer
The observer pattern is perhaps the most used pattern in the JavaScript world. The pattern is used especially with modern single page applications; it is a big part of the various libraries that provide the Model-View-ViewModel (MVVM) functionality. We'll explore those patterns in some detail in Chapter 7, Model View Patterns.
It is frequently useful to know when the value of an object has changed. In order to do so, you could wrap up the property of interest with a getter and a setter:
var GetterSetter = (function () { function GetterSetter() { } GetterSetter.prototype.GetProperty = function () { return this._property; }; GetterSetter.prototype.SetProperty = function (value) { this._property = value; }; return GetterSetter; })();
The setter function can now be augmented with a call to some other object that is interested in knowing that a value has changed:
GetterSetter.prototype.SetProperty = function (value) { var temp = this._property; this._property = value; this._listener.Event(value, temp); };
This setter will now notify the listener that a property change has occurred. In this case, both the old and new value have been included. This is not necessary as the listener can be tasked with keeping track of the previous value.
The observer pattern generalizes and codifies this idea. Instead of having a single call to the listener, the observer pattern allows interested parties to subscribe to change notifications. The following diagram explains the observer pattern:
Implementation
The court of Westeros is a place of great intrigue and trickery. Controlling who is on the throne and what moves they make is a complex game. Many of the players in the game of thrones employ numerous spies to discover what moves others are making. Frequently, these spies are employed by more than one player and must report what they have found to all of the players.
The spy is a perfect place to employ the observer pattern. In our particular example, the spy being employed is the official doctor to the king and the players are very interested in knowing how much pain killer is being prescribed to the ailing king. This can give a player advanced knowledge of when the king might die—a most useful piece of information.
The spy looks like the following code:
var Spy = (function () { function Spy() { this._partiesToNotify = []; } Spy.prototype.Subscribe = function (subscriber) { this._partiesToNotify.push(subscriber); }; Spy.prototype.Unsubscribe = function (subscriber) { this._partiesToNotify.remove(subscriber); }; Spy.prototype.SetPainKillers = function (painKillers) { this._painKillers = painKillers; for (var i = 0; i < this._partiesToNotify.length; i++) { this._partiesToNotify[i](painKillers); } }; return Spy; })();
In other languages, the subscriber usually has to comply with a certain interface and the observer will call only the interface method. The encumbrance doesn't exist with JavaScript and, in fact, we just give the Spy
class a function. This means that there is no strict interface required for the subscriber.
The following code is an example:
var Player = (function () { function Player() { } Player.prototype.OnKingPainKillerChange = function (newPainKillerAmount) { //perform some action }; return Player; })();
This can be used as follows:
var s = new Spy(); var p = new Player(); s.Subscribe(p.OnKingPainKillerChange); //p is now a subscriber s.SetPainKillers(12); //s will notify all subscribers
This provides a very simple and highly effective way of building observers. Having subscribers decouples the subscriber from the observable object.
The observer pattern can also be applied to methods as well as properties. In doing so, you can provide hooks for additional behavior to happen. This is a common method of providing a plugin infrastructure for JavaScript libraries.
In browsers, all the event listeners on various items in the DOM are implemented using the observer pattern. For instance, using the popular jQuery library, one can subscribe to all the click events on buttons on a page with the following line:
$("body").on("click", "button", function(){/*do something*/})
Even in Vanilla JavaScript, the same pattern applies:
var buttons = document.getElementsByTagName("button"); for(var i =0; i< buttons.length; i++) { buttons[i].onclick = function(){/*do something*/} }
Clearly, the observer pattern is a very useful one when dealing with JavaScript. There is no need to change the pattern in any significant fashion.
Implementation
The court of Westeros is a place of great intrigue and trickery. Controlling who is on the throne and what moves they make is a complex game. Many of the players in the game of thrones employ numerous spies to discover what moves others are making. Frequently, these spies are employed by more than one player and must report what they have found to all of the players.
The spy is a perfect place to employ the observer pattern. In our particular example, the spy being employed is the official doctor to the king and the players are very interested in knowing how much pain killer is being prescribed to the ailing king. This can give a player advanced knowledge of when the king might die—a most useful piece of information.
The spy looks like the following code:
var Spy = (function () { function Spy() { this._partiesToNotify = []; } Spy.prototype.Subscribe = function (subscriber) { this._partiesToNotify.push(subscriber); }; Spy.prototype.Unsubscribe = function (subscriber) { this._partiesToNotify.remove(subscriber); }; Spy.prototype.SetPainKillers = function (painKillers) { this._painKillers = painKillers; for (var i = 0; i < this._partiesToNotify.length; i++) { this._partiesToNotify[i](painKillers); } }; return Spy; })();
In other languages, the subscriber usually has to comply with a certain interface and the observer will call only the interface method. The encumbrance doesn't exist with JavaScript and, in fact, we just give the Spy
class a function. This means that there is no strict interface required for the subscriber.
The following code is an example:
var Player = (function () { function Player() { } Player.prototype.OnKingPainKillerChange = function (newPainKillerAmount) { //perform some action }; return Player; })();
This can be used as follows:
var s = new Spy(); var p = new Player(); s.Subscribe(p.OnKingPainKillerChange); //p is now a subscriber s.SetPainKillers(12); //s will notify all subscribers
This provides a very simple and highly effective way of building observers. Having subscribers decouples the subscriber from the observable object.
The observer pattern can also be applied to methods as well as properties. In doing so, you can provide hooks for additional behavior to happen. This is a common method of providing a plugin infrastructure for JavaScript libraries.
In browsers, all the event listeners on various items in the DOM are implemented using the observer pattern. For instance, using the popular jQuery library, one can subscribe to all the click events on buttons on a page with the following line:
$("body").on("click", "button", function(){/*do something*/})
Even in Vanilla JavaScript, the same pattern applies:
var buttons = document.getElementsByTagName("button"); for(var i =0; i< buttons.length; i++) { buttons[i].onclick = function(){/*do something*/} }
Clearly, the observer pattern is a very useful one when dealing with JavaScript. There is no need to change the pattern in any significant fashion.
State
State machines are an amazingly useful device in computer programming. Unfortunately, they are not used very frequently by most programmers. I'm sure that at least some of the objection to state machines is that many people implement them as a giant if
statement, as shown in the following code:
function (action, amount) { if (this.state == "overdrawn" && action == "withdraw") { this.state = "on hold"; } if (this.state == "on hold" && action != "deposit") { this.state = "on hold"; } if (this.state == "good standing" && action == "withdraw" && amount <= this.balance) { this.balance -= amount; } if (this.state == "good standing" && action == "withdraw" && amount >this.balance) { this.balance -= amount; this.state = "overdrawn"; } };
This is just a sample of what could be a much more complicated workflow. if
statements of this length are painful to debug and highly error prone. Simply flipping a greater than sign is enough to drastically change how the if
statement works.
Instead of using a single giant if
statement block, we can make use of the state pattern. The state pattern is characterized by having a state manager that abstracts away the internal state and proxies message through to the appropriate state that is implemented as a class. All the logic within states and governing state transitions is governed by the individual state classes. The following diagram explains the state pattern:
Splitting state into a class per state allows for much smaller blocks of code to debug and makes testing much easier.
The interface for the state manager is fairly simple and usually just provides the methods needed to communicate with the individual states. The manager may also contain some shared state variables.
Implementation
As alluded to in the if
statement example, Westeros has a banking system. Much of it is centered on the island of Braavos. Banking there runs in much the same way as banking here, with accounts, deposits, and withdrawals. Managing the state of a bank account involves keeping an eye on all of the transactions and changing the state of the bank account in accordance with the transactions.
Let's take a look at some of the code that is needed to manage a bank account at the Iron Bank of Braavos. First is the state manager:
var BankAccountManager = (function () { function BankAccountManager() { this.currentState = new GoodStandingState(this); } BankAccountManager.prototype.Deposit = function (amount) { this.currentState.Deposit(amount); }; BankAccountManager.prototype.Withdraw = function (amount) { this.currentState.Withdraw(amount); }; BankAccountManager.prototype.addToBalance = function (amount) { this.balance += amount; }; BankAccountManager.prototype.getBalance = function () { return this.balance; }; BankAccountManager.prototype.moveToState = function (newState) { this.currentState = newState; }; return BankAccountManager; })();
The bank account manager class provides a state for the current balance and also the current state. To protect the balance, it provides an accessor to read the balance and another to add to the balance. In a real banking application, I would rather expect that the function to set the balance would have more protection than this. In this version of the bank manager, the ability to manipulate the current state is accessible to the states. They have the responsibility to change states. This functionality can be centralized in the manger but that increases the complexity of adding new states.
We've identified three simple states for the bank account: overdrawn, on hold, and good standing. Each one is responsible to deal with withdrawals and deposits when in that state. The GoodStandingState
class looks like the following code:
var GoodStandingState = (function () { function GoodStandingState(manager) { this.manager = manager; } GoodStandingState.prototype.Deposit = function (amount) { this.manager.addToBalance(amount); }; GoodStandingState.prototype.Withdraw = function (amount) { if (this.manager.getBalance() < amount) { this.manager.moveToState(new OverdrawnState(this.manager)); } this.manager.addToBalance(-1 * amount); }; return GoodStandingState; })();
The overdrawn state looks like the following code:
var OverdrawnState = (function () { function OverdrawnState(manager) { this.manager = manager; } OverdrawnState.prototype.Deposit = function (amount) { this.manager.addToBalance(amount); if (this.manager.getBalance() > 0) { this.manager.moveToState(new GoodStandingState(this.manager)); } }; OverdrawnState.prototype.Withdraw = function (amount) { this.manager.moveToState(new OnHold(this.manager)); throw "Cannot withdraw money from an already overdrawn bank account"; }; return OverdrawnState; })();
Finally, the OnHold
state looks like the following code:
var OnHold = (function () { function OnHold(manager) { this.manager = manager; } OnHold.prototype.Deposit = function (amount) { this.manager.addToBalance(amount); throw "Your account is on hold and you must go to the bank to resolve the issue"; }; OnHold.prototype.Withdraw = function (amount) { throw "Your account is on hold and you must go to the bank to resolve the issue"; }; return OnHold; })();
You can see that we've managed to reproduce all the logic of the confusing if
statement in a number of simple classes. The amount of code here looks to be far more than the if
statements, but in the long run encapsulating the code into individual classes will pay off.
There is plenty of opportunity to make use of this pattern within JavaScript. Keeping track of the state is a typical problem in most applications. When the transitions between states is complex, then wrapping it up in a state pattern is one method of simplifying things. It is also possible to build up a simple workflow by registering events as sequential. A nice interface for this might be a fluent one so that you could register states as follows:
goodStandingState .on("withdraw") .when(function(manager){return manager.balance > 0;}) .transitionTo("goodStanding") .when(function(manager){return mangaer.balance <=0;}) .transitionTo("overdrawn");
Implementation
As alluded to in the if
statement example, Westeros has a banking system. Much of it is centered on the island of Braavos. Banking there runs in much the same way as banking here, with accounts, deposits, and withdrawals. Managing the state of a bank account involves keeping an eye on all of the transactions and changing the state of the bank account in accordance with the transactions.
Let's take a look at some of the code that is needed to manage a bank account at the Iron Bank of Braavos. First is the state manager:
var BankAccountManager = (function () { function BankAccountManager() { this.currentState = new GoodStandingState(this); } BankAccountManager.prototype.Deposit = function (amount) { this.currentState.Deposit(amount); }; BankAccountManager.prototype.Withdraw = function (amount) { this.currentState.Withdraw(amount); }; BankAccountManager.prototype.addToBalance = function (amount) { this.balance += amount; }; BankAccountManager.prototype.getBalance = function () { return this.balance; }; BankAccountManager.prototype.moveToState = function (newState) { this.currentState = newState; }; return BankAccountManager; })();
The bank account manager class provides a state for the current balance and also the current state. To protect the balance, it provides an accessor to read the balance and another to add to the balance. In a real banking application, I would rather expect that the function to set the balance would have more protection than this. In this version of the bank manager, the ability to manipulate the current state is accessible to the states. They have the responsibility to change states. This functionality can be centralized in the manger but that increases the complexity of adding new states.
We've identified three simple states for the bank account: overdrawn, on hold, and good standing. Each one is responsible to deal with withdrawals and deposits when in that state. The GoodStandingState
class looks like the following code:
var GoodStandingState = (function () { function GoodStandingState(manager) { this.manager = manager; } GoodStandingState.prototype.Deposit = function (amount) { this.manager.addToBalance(amount); }; GoodStandingState.prototype.Withdraw = function (amount) { if (this.manager.getBalance() < amount) { this.manager.moveToState(new OverdrawnState(this.manager)); } this.manager.addToBalance(-1 * amount); }; return GoodStandingState; })();
The overdrawn state looks like the following code:
var OverdrawnState = (function () { function OverdrawnState(manager) { this.manager = manager; } OverdrawnState.prototype.Deposit = function (amount) { this.manager.addToBalance(amount); if (this.manager.getBalance() > 0) { this.manager.moveToState(new GoodStandingState(this.manager)); } }; OverdrawnState.prototype.Withdraw = function (amount) { this.manager.moveToState(new OnHold(this.manager)); throw "Cannot withdraw money from an already overdrawn bank account"; }; return OverdrawnState; })();
Finally, the OnHold
state looks like the following code:
var OnHold = (function () { function OnHold(manager) { this.manager = manager; } OnHold.prototype.Deposit = function (amount) { this.manager.addToBalance(amount); throw "Your account is on hold and you must go to the bank to resolve the issue"; }; OnHold.prototype.Withdraw = function (amount) { throw "Your account is on hold and you must go to the bank to resolve the issue"; }; return OnHold; })();
You can see that we've managed to reproduce all the logic of the confusing if
statement in a number of simple classes. The amount of code here looks to be far more than the if
statements, but in the long run encapsulating the code into individual classes will pay off.
There is plenty of opportunity to make use of this pattern within JavaScript. Keeping track of the state is a typical problem in most applications. When the transitions between states is complex, then wrapping it up in a state pattern is one method of simplifying things. It is also possible to build up a simple workflow by registering events as sequential. A nice interface for this might be a fluent one so that you could register states as follows:
goodStandingState .on("withdraw") .when(function(manager){return manager.balance > 0;}) .transitionTo("goodStanding") .when(function(manager){return mangaer.balance <=0;}) .transitionTo("overdrawn");
Strategy
It has been said that there is more than one way to skin a cat. I have, wisely, never looked into how many ways there are. The same is frequently true for algorithms in computer programming. Frequently, there are numerous versions of an algorithm that trade off memory usage for CPU usage. Sometimes, there are different approaches that provide different levels of fidelity. For example, performing a geolocation on a smart phone typically uses one of three different sources of data:
- GPS chips
- Cell phone triangulation
- Nearby WiFi points
Using the GPS chip provides the highest level of fidelity; however, it is also the slowest and requires the most battery. Looking at the nearby WiFi points requires very little energy and is very quick; however, it provides poor fidelity.
The strategy pattern provides a method of swapping these strategies out in a transparent fashion. In a traditional inheritance model, each strategy would implement the same interface, which would allow for any of the strategies to be swapped in. The following diagram describes the strategy pattern:
Selecting the correct strategy to use can be done in a number of different ways. The simplest method is to select the strategy statically. This can be done through a configuration variable or can even be hardcoded. This approach is best for times when the strategy changes infrequently or is specific to a single customer or user.
Alternately, an analysis can be run on the dataset on which the strategy is to be run and then a proper strategy selected. If it is known that strategy A works better than strategy B when the data passed in is clustered around a mean, then a fast algorithm to analyze the spread could be run first and then the appropriate strategy selected.
If a particular algorithm fails on data of a certain type, this too can be taken into consideration when choosing a strategy. In a web application, this can be used to call a different API depending on the shape of data. It can also be used to provide a fallback mechanism should one of the API endpoints be down.
Another interesting approach is to use progressive enhancement. The fastest and least accurate algorithm is run first to provide rapid user feedback. At the same time, a slower algorithm is also run, and when it is finished the superior results are used to replace the existing results. This approach is frequently used in the GPS situation outlined earlier. You may notice when using a map on a mobile device that your location is updated a moment after the map loads; this is an example of progressive enhancement.
Finally, the strategy can be chosen completely at random. It sounds like a strange approach but can be useful when comparing the performance of two different strategies. In this case, statistics would be gathered about how well each approach works and an analysis run to select the best strategy. The strategy pattern can be the foundation for A/B testing.
Selecting which strategy to use can be an excellent place to apply the factory pattern.
Implementation
In the land of Westeros, there are no planes, trains, or automobiles but there is still a wide variety of different ways to travel. One can walk, ride a horse, sail on a sea-going vessel, or even take a boat down the river. Each one has different advantages and drawbacks but in the end they still take a person from point A to point B. The interface might look something like the following code:
export interface ITravelMethod{ Travel(source: string, destination: string) : TravelResult; }
The travel result communicates back to the caller some information about the method of travel. In our case, we track how long the trip will take, what the risks are, and how much it will cost:
var TravelResult = (function () { function TravelResult(durationInDays, probabilityOfDeath, cost) { this.durationInDays = durationInDays; this.probabilityOfDeath = probabilityOfDeath; this.cost = cost; } return TravelResult; })(); Travel.TravelResult = TravelResult;
In this scenario, we might like to have an additional method that predicts some of the risks, to allow for automating selection of a strategy.
Implementing the strategies is as simple as:
var SeaGoingVessel = (function () { function SeaGoingVessel() { } SeaGoingVessel.prototype.Travel = function (source, destination) { return new TravelResult(15, .25, 500); }; return SeaGoingVessel; })(); var Horse = (function () { function Horse() { } Horse.prototype.Travel = function (source, destination) { return new TravelResult(30, .25, 50); }; return Horse; })(); var Walk = (function () { function Walk() { } Walk.prototype.Travel = function (source, destination) { return new TravelResult(150, .55, 0); }; return Walk; })();
In a traditional implementation of the strategy pattern, the method signature for each strategy should be the same. In JavaScript, there is a bit more flexibility, as excess parameters to a function are ignored and missing parameters can be given default values.
Obviously, the actual calculations around risk, cost, and duration would not be hardcoded in an actual implementation. To make use of these, one needs only to use the following code:
var currentMoney = getCurrentMoney(); var strat; if (currentMoney > 500) strat = new SeaGoingVessel(); else if (currentMoney > 50) strat = new Horse(); else strat = new Walk(); var travelResult = strat.Travel();
To improve the level of abstraction for this strategy, we might replace the specific strategies with more generally named ones that describe what it is we're optimizing for:
var currentMoney = getCurrentMoney(); var strat; if (currentMoney > 500) strat = new FavorFastestAndSafestStrategy(); else strat = new FavorCheapest(); var travelResult = strat.Travel();
Strategy is a very useful pattern in JavaScript. We're also able to make the approach much simpler than in a language that doesn't use prototype inheritance: there is no need for an interface. We don't need to return the same shaped object from each of the different strategies. So long as the caller is somewhat aware that the returned object may have additional fields, this is a perfectly reasonable, if difficult to maintain, approach.
Implementation
In the land of Westeros, there are no planes, trains, or automobiles but there is still a wide variety of different ways to travel. One can walk, ride a horse, sail on a sea-going vessel, or even take a boat down the river. Each one has different advantages and drawbacks but in the end they still take a person from point A to point B. The interface might look something like the following code:
export interface ITravelMethod{ Travel(source: string, destination: string) : TravelResult; }
The travel result communicates back to the caller some information about the method of travel. In our case, we track how long the trip will take, what the risks are, and how much it will cost:
var TravelResult = (function () { function TravelResult(durationInDays, probabilityOfDeath, cost) { this.durationInDays = durationInDays; this.probabilityOfDeath = probabilityOfDeath; this.cost = cost; } return TravelResult; })(); Travel.TravelResult = TravelResult;
In this scenario, we might like to have an additional method that predicts some of the risks, to allow for automating selection of a strategy.
Implementing the strategies is as simple as:
var SeaGoingVessel = (function () { function SeaGoingVessel() { } SeaGoingVessel.prototype.Travel = function (source, destination) { return new TravelResult(15, .25, 500); }; return SeaGoingVessel; })(); var Horse = (function () { function Horse() { } Horse.prototype.Travel = function (source, destination) { return new TravelResult(30, .25, 50); }; return Horse; })(); var Walk = (function () { function Walk() { } Walk.prototype.Travel = function (source, destination) { return new TravelResult(150, .55, 0); }; return Walk; })();
In a traditional implementation of the strategy pattern, the method signature for each strategy should be the same. In JavaScript, there is a bit more flexibility, as excess parameters to a function are ignored and missing parameters can be given default values.
Obviously, the actual calculations around risk, cost, and duration would not be hardcoded in an actual implementation. To make use of these, one needs only to use the following code:
var currentMoney = getCurrentMoney(); var strat; if (currentMoney > 500) strat = new SeaGoingVessel(); else if (currentMoney > 50) strat = new Horse(); else strat = new Walk(); var travelResult = strat.Travel();
To improve the level of abstraction for this strategy, we might replace the specific strategies with more generally named ones that describe what it is we're optimizing for:
var currentMoney = getCurrentMoney(); var strat; if (currentMoney > 500) strat = new FavorFastestAndSafestStrategy(); else strat = new FavorCheapest(); var travelResult = strat.Travel();
Strategy is a very useful pattern in JavaScript. We're also able to make the approach much simpler than in a language that doesn't use prototype inheritance: there is no need for an interface. We don't need to return the same shaped object from each of the different strategies. So long as the caller is somewhat aware that the returned object may have additional fields, this is a perfectly reasonable, if difficult to maintain, approach.
Template method
The strategy pattern allows replacing an entire algorithm with a complimentary one. Frequently replacing the entire algorithm is overkill: the vast majority of the algorithm remains the same in every strategy with only minor variations in specific sections.
The template method pattern is an approach that allows for some sections of an algorithm to be shared and other sections be implemented using different approaches. These farmed out sections can be implemented by any one of a family of methods. The following diagram describes the template method pattern:
The template class implements parts of the algorithm and leaves other parts as abstract to be overridden later by classes that extend it. The inheritance hierarchy can be several layers deep, with each level implementing more and more of the template class.
Tip
An abstract class is one that contains abstract methods. Abstract methods are simply methods that have no body to them. The abstract class cannot be used directly and must, instead, be extended by another class that implements the abstract methods. An abstract class may extend another abstract class so that not all methods need to be implemented by the extending class.
This approach applies the principles of progressive enhancement to an algorithm. We move closer and closer to a fully implemented algorithm, and at the same time build up an interesting inheritance tree. The template method helps keep identical code to a single location while still allowing for some deviation. This diagram shows a chain of partial implementations:
Overriding methods left as abstract is a quintessential part of object-oriented programming. It is likely that this pattern is one which you've used frequently without even being aware that it had a name.
Implementation
I have been told, by those in the know, that there are many different ways to produce beer. These beers differ in their choice of ingredients and in their method of production. In fact, beer does not even need to contain hops—it can be made from any number of grains. However, there are similarities between all beers. They are all created through the fermentation process and all proper beers contain some amount of alcohol.
In Westeros, there are a large number of craftsmen who pride themselves on creating top notch beers. We would like to describe their processes as a set of classes, each one describing a different beer-making methodology. We start with a simplified implementation of creating beer:
var BasicBeer = (function () { function BasicBeer() { } BasicBeer.prototype.Create = function () { this.AddIngredients(); this.Stir(); this.Ferment(); this.Test(); if (this.TestingPassed()) { this.Distribute(); } }; BasicBeer.prototype.AddIngredients = function () { throw "Add ingredients needs to be implemented"; }; BasicBeer.prototype.Stir = function () { //stir 15 times with a wooden spoon }; BasicBeer.prototype.Ferment = function () { //let stand for 30 days }; BasicBeer.prototype.Test = function () { //draw off a cup of beer and taste it }; BasicBeer.prototype.TestingPassed = function () { throw "Conditions to pass a test must be implemented"; }; BasicBeer.prototype.Distribute = function () { //place beer in 50L casks }; return BasicBeer; })();
As there is no concept of abstract in JavaScript, we've added exceptions to the various methods that must be overridden. The remaining methods can be changed but do not require it. An implementation of this for raspberry beer would look like the following code:
var RaspberryBeer = (function (_super) { __extends(RaspberryBeer, _super); function RaspberryBeer() { _super.apply(this, arguments); } RaspberryBeer.prototype.AddIngredients = function () { //add ingredients, probably including raspberries }; RaspberryBeer.prototype.TestingPassed = function () { //beer must be reddish and taste of raspberries }; return RaspberryBeer; })(BasicBeer);
Additional subclassing may be performed at this stage for more specific raspberry beers.
The template method remains a fairly useful pattern in JavaScript. There is some added syntactic sugar around creating classes, but it isn't anything we haven't already seen in a previous chapter. The only warning I would give is that the template method uses inheritance and thus strongly couples the inherited classes with the parent class. This is generally not a desirable state of affairs.
Implementation
I have been told, by those in the know, that there are many different ways to produce beer. These beers differ in their choice of ingredients and in their method of production. In fact, beer does not even need to contain hops—it can be made from any number of grains. However, there are similarities between all beers. They are all created through the fermentation process and all proper beers contain some amount of alcohol.
In Westeros, there are a large number of craftsmen who pride themselves on creating top notch beers. We would like to describe their processes as a set of classes, each one describing a different beer-making methodology. We start with a simplified implementation of creating beer:
var BasicBeer = (function () { function BasicBeer() { } BasicBeer.prototype.Create = function () { this.AddIngredients(); this.Stir(); this.Ferment(); this.Test(); if (this.TestingPassed()) { this.Distribute(); } }; BasicBeer.prototype.AddIngredients = function () { throw "Add ingredients needs to be implemented"; }; BasicBeer.prototype.Stir = function () { //stir 15 times with a wooden spoon }; BasicBeer.prototype.Ferment = function () { //let stand for 30 days }; BasicBeer.prototype.Test = function () { //draw off a cup of beer and taste it }; BasicBeer.prototype.TestingPassed = function () { throw "Conditions to pass a test must be implemented"; }; BasicBeer.prototype.Distribute = function () { //place beer in 50L casks }; return BasicBeer; })();
As there is no concept of abstract in JavaScript, we've added exceptions to the various methods that must be overridden. The remaining methods can be changed but do not require it. An implementation of this for raspberry beer would look like the following code:
var RaspberryBeer = (function (_super) { __extends(RaspberryBeer, _super); function RaspberryBeer() { _super.apply(this, arguments); } RaspberryBeer.prototype.AddIngredients = function () { //add ingredients, probably including raspberries }; RaspberryBeer.prototype.TestingPassed = function () { //beer must be reddish and taste of raspberries }; return RaspberryBeer; })(BasicBeer);
Additional subclassing may be performed at this stage for more specific raspberry beers.
The template method remains a fairly useful pattern in JavaScript. There is some added syntactic sugar around creating classes, but it isn't anything we haven't already seen in a previous chapter. The only warning I would give is that the template method uses inheritance and thus strongly couples the inherited classes with the parent class. This is generally not a desirable state of affairs.
Visitor
The final pattern in this section is the visitor pattern. Visitor provides for a method of decoupling an algorithm from the object structure on which it operates. If we wanted to perform some action over a collection of objects that differ in type and we want to perform a different action depending on the object type, we would typically need to make use of a large if
statement.
Let's get right into an example of this in Westeros. An army is made up of a few different classes of fighting persons (it is important that we be politically correct as there are many notable female fighters in Westeros). However, each member of the army implements a hypothetical interface called
IMemberOfArmy
:
interface IMemberOfArmy{ printName(); }
A simple implementation of this might be:
var Knight = (function () { function Knight() { } Knight.prototype.printName = function () { console.log("Knight"); }; return Knight; })();
Now that we have a collection of these different types, we can use an if
statement to only call the printName
function on the knights:
var collection = []; collection.push(new Knight()); collection.push(new FootSoldier()); collection.push(new Lord()); collection.push(new Archer()); for (var i = 0; i < collection.length; i++) { if (typeof (collection[i]) == 'Knight') collection[i].printName(); else console.log("Not a knight"); }
Except if you run the preceding code, you'll actually find that all we get is:
Not a knight Not a knight Not a knight Not a knight
This is because, despite an object being a knight, it is still an object and typeof
will return the object in all cases.
An alternative approach is to use instanceof
instead of typeof
:
var collection = []; collection.push(new Knight()); collection.push(new FootSoldier()); collection.push(new Lord()); collection.push(new Archer()); for (var i = 0; i < collection.length; i++) { if (collection[i] instanceof Knight) collection[i].printName(); else console.log("No match"); }
The instance of approach works great until we run into somebody who makes use of the Object.create
syntax:
collection.push(Object.create(Knight));
Despite being the Knight
class, this will return false
when asked if it is an instance of the Knight
class.
This poses something of a problem for us. The problem is exacerbated by the visitor pattern as it requires that the language support method overloading. JavaScript does not really support this. There are various hacks that can be used to make JavaScript somewhat aware of overloaded methods, but the usual advice is to simply not bother and create methods with different names.
Let's not abandon this pattern just yet, though; it is a useful pattern. What we need is a way to reliably distinguish one type from another. The simplest approach is to just define a variable on the class that denotes its type:
var Knight = (function () { function Knight() { this._type = "Knight"; } Knight.prototype.printName = function () { console.log("Knight"); }; return Knight; })();
Given the new _type
variable, we can now fake having real method overrides:
var collection = []; collection.push(new Knight()); collection.push(new FootSoldier()); collection.push(new Lord()); collection.push(new Archer()); for (var i = 0; i < collection.length; i++) { if (collection[i]._type == 'Knight') collection[i].printName(); else console.log("No match"); }
Given this approach, we can now implement the visitor pattern. The first step is to expand the various members of our army to have a generic method on them that takes a visitor
and applies it:
var Knight = (function () { function Knight() { this._type = "Knight"; } Knight.prototype.printName = function () { console.log("Knight"); }; Knight.prototype.visit = function (visitor) { visitor.visit(this); }; return Knight; })();
Now, we need to build a visitor. The following code approximates the if
statements we had in the previous code:
var SelectiveNamePrinterVisitor = (function () { function SelectiveNamePrinterVisitor() { } SelectiveNamePrinterVisitor.prototype.Visit = function (memberOfArmy) { if (memberOfArmy._type == "Knight") { this.VisitKnight(memberOfArmy); } else { console.log("Not a knight"); } }; SelectiveNamePrinterVisitor.prototype.VisitKnight = function (memberOfArmy) { memberOfArmy.printName(); }; return SelectiveNamePrinterVisitor; })();
This visitor would be used as such:
var collection = []; collection.push(new Knight()); collection.push(new FootSoldier()); collection.push(new Lord()); collection.push(new Archer()); var visitor = new SelectiveNamePrinterVisitor(); for (var i = 0; i < collection.length; i++) { collection[i].visit(visitor); }
As you can see, we've pushed the decisions about what is the type of the item in the collection down to the visitor. This decouples the items themselves from the visitor, as shown in the following diagram:
If we allow the visitor itself to make decisions about what methods are called on the visited objects, there is a fair bit of trickery required. If we can provide a constant interface for the visited objects, then all the visitor needs do is call the interface method. This does, however, move logic from the visitor into the objects that are visited, which is contrary to the idea that the objects shouldn't know that they are part of a visitor.
Whether suffering through the trickery is worthwhile or not, it is definitely an exercise for you. Personally, I would tend to avoid using the visitor pattern in JavaScript, as the requirements to get it working are complicated and non-obvious.
Hints and tips
Here are a couple of brief tips to keep in mind about some of the patterns we've seen in this chapter:
- When implementing the interpreter pattern, you may be tempted to use JavaScript properly as your DSL and then use the
eval
function to execute the code. This is actually a very dangerous idea aseval
opens up an entire world of security issues. It is generally considered to be very bad form to useeval
in JavaScript. - If you find yourself in a position to audit the changes to data in your project, then the memento pattern can easily be modified to suit this. Instead of just keeping track of the state changes, you can also track when the change was made and who made the change. Saving these mementos to disk somewhere allows you to go back and, rapidly, build an audit log pointing to precisely what happened to change the object.
- The observer pattern is notorious as it causes memory leaks when listeners aren't properly unregistered. This can happen even in a memory managed environment such as JavaScript. Be wary of failing to unhook observers.
Summary
In this chapter, we've looked at a bunch of behavioral patterns. Some of these patterns, such as observers and iterators, will be ones you'll use almost every day, while others, such as interpreters, you might use no more than a handful of times in your entire career. Learning about these patterns should help you identify well-defined solutions to common problems.
Most of the patterns are directly applicable to JavaScript and some of them, such as the strategy pattern, become more powerful in a dynamic language. The only pattern we found that has some limitations is the visitor pattern. The lack of static classes and polymorphism makes this pattern difficult to implement without breaking proper separation of concerns.
These are, by no means, all of the behavioral patterns in existence. The programming community has spent the past two decades building on the ideas of the GoF book and identifying new patterns. The remainder of this book is dedicated to these newly identified patterns. The solutions may be very old ones but were not generally recognized as common solutions until more recently. As far as I'm concerned, this is the point where the book starts to get very interesting, as we start looking at less well-known and more JavaScript-specific patterns.