Skip to content

Commit 56671fb

Browse files
author
Badacadabra
committed
Add README files for idiomatic patterns
1 parent fa55a0c commit 56671fb

File tree

23 files changed

+403
-0
lines changed

23 files changed

+403
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Synopsis
2+
3+
Imagine a long relay race with athletes from different sports. This race could involve several teams composed each time of a racewalker, a runner and a swimmer.
4+
5+
# Problem
6+
7+
Each sport has its own rules and each athlete will participate differently. So we cannot just evaluate the role of each athlete in the same way, even though the objective is the same for everyone within a team: the gold medal. A swimmer and a runner are both athletes, but a swimmer swims whereas a runner runs... Here we could say that each team member handles a part of the initial request which is to win the race.
8+
9+
Moreover, this is a relay race, not an individual one. Each athlete must know the next relay where another athlete will wait for the baton before to start.
10+
11+
# Solution
12+
13+
Everytime a request should be handled by multiple (and complementary) processing units, the Chain of Responsibility pattern seems ideal. In this case, we can represent each athlete with a simple object literal. We will have:
14+
15+
* An object literal representing a walker
16+
* An object literal representing a runner
17+
* An object literal representing a swimmer
18+
19+
Each of these objects should have at least their own method ("go") whose action will be specific to the associated sport. But each of these particular "go" methods will also transfer some work to the next relay, chosen by the client code.
20+
21+
N.B. This design pattern should not be confused with simple method chaining in JavaScript.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Synopsis
2+
3+
I am hungry and I decide to call the nearest Tex-Mex restaurant to place an order. I hope I will receive my meal fast.
4+
5+
# Problem
6+
7+
Placing an order is easy to do. As a customer, you only need to say what you want to eat and nothing else. However, for the restaurant, there is a true organization behind the scenes to effectively treat your order. The chef cooks for you, then the meal is packaged and finally the delivery man brings it to you as fast as possible. Plus, you are not the only one to be hungry... The restaurant is most likely in a situation where it has to handle many orders, especially when it is time for dinner.
8+
9+
In computer science terms, it seems obvious that the restaurant has to handle a queue of orders and that each customer is a unique entity. Since a customer normally pays his order to the delivery man, the payment should be the last step of the process. But this is not so intuitive if you try to find a good code organization for this. On the one hand, all orders are handled by the restaurant and everything required to prepare these orders is like encapsulated in each order. On the other hand, only customers can validate orders since their responsible for payment.
10+
11+
# Solution
12+
13+
The Command pattern is a great help here. In this pattern terminology, we will say that:
14+
***
15+
* The restaurant is the "invoker" who creates and handles new orders internally.
16+
* The order is the "command", in other words the request which comes from a client.
17+
* The customer is the "receiver" of the order.
18+
19+
To implement this pattern, we then need three object literals to represent each entity:
20+
21+
* The customer has only one method ("pay").
22+
* The order has a reference to a given customer and makes him pay using its "deliver" method.
23+
* The restaurant is a more complex object with a collection (array) of orders and an essential method ("prepareOrders") that start the delivery of each order.
24+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Synopsis
2+
3+
I love music and I want to be able to analyze some compositions like "Moonlight Sonata" by Beethoven.
4+
5+
# Problem
6+
7+
Music is a beautiful but complex universe, and listening to music does not mean understanding it. To analyze compositions, music theory is an absolute necessity. Since music is a language, pretty much like English or French are, it has its own grammar. Understanding this grammar makes it possible to understand a composition. But here the question is: how do we describe a grammar with a programming language?
8+
9+
# Solution
10+
11+
The Interpreter pattern is exactly what we need to tell JavaScript how to interpret music grammar. Here we can have:
12+
13+
* Factory functions to create expressions (especially notes and arpeggios)
14+
* A basic object literal to represent the context (the sonata)
15+
16+
The distinction between terminal and nonterminal expressions in the Interpreter pattern is a bit like the distinction between simple and composed elements in the Composite pattern. A note is a terminal expression because it is an "elementary symbol" of the grammar. However, an arpeggio is a nonterminal expression because it can be considered as a group of notes.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Synopsis
2+
3+
I am at the library and I would like to see the list of all available books.
4+
5+
# Problem
6+
7+
There is generally a huge amount of books in a library, so it is great to have a catalog that allows you to have a quick overview of all available references. This catalog may be a bit special and could contain a one-page presentation for each book.
8+
9+
In Javascript, we could use a simple loop to get the list of all books. But in fact, this would not be so convenient because each data structure and entity may have its own particularities when it comes to iteration. For instance, we know we cannot iterate through an array literal like we iterate through an object literal (array-like objects could be considered as an exception). Therefore this is generally a good idea to simplify the work to iterate through a collection...
10+
11+
# Solution
12+
13+
Iterator is the design pattern we need for this. To implement this pattern, we could have:
14+
15+
* An object literal containing an index property and at least a method named "next"
16+
* A very basic object literal representing a library (which is a collection of books)
17+
18+
In this particular case, a collection is an iterable object whereas a catalog is an iterator object.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Synopsis
2+
3+
Tom and Dick are neighbors. Dick makes a lot of noise on Sunday mornings, which drives Tom crazy. Communication has become difficult between them because of this.
4+
5+
# Problem
6+
7+
If Tom and Dick cannot talk to each other directly, Dick will continue to make noise and Tom will get angry every Sunday.
8+
9+
# Solution
10+
11+
When communication is difficult between two objects or in a system (here the neighborhood), the solution is delegation to a third-party object. This object will make communication easier between all other objects.
12+
13+
This is exactly the solution proposed by the Mediator pattern. To implement this pattern, we need:
14+
15+
* Object literals to represent Tom and Dick (who are neighbors)
16+
* An object literal to represent Harry (who is the mediator)
17+
18+
Tom and Dick have both a "send" and "receive" methods, but they do not communicate directly. They communicate through the mediator who acts a bit like a router. Thus, Harry must have a reference to both neighbor objects and, depending on the sender, he will know the receiver...
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Synopsis
2+
3+
I found an interesting article on the Web and I would like to save it in my browser for later reading. For some reasons, I always use private browsing.
4+
5+
# Problem
6+
7+
With private browsing, history is not kept by the browser. Of course we can use back and forward buttons to navigate in the current history during the browsing session, but with this technique, it would not be possible to identify easily our favorite webpages. Furthermore, interesting webpages would not be there anymore if we close the browser and open it again.
8+
9+
# Solution
10+
11+
Here we have to use bookmarks to save interesting webpages and the Memento pattern allows us to simulate that behavior. We can implement this pattern using:
12+
13+
* An object literal with a "saveCurrentPage" method to represent the browser (this is the "originator")
14+
* An object literal containing a collection (array) of bookmarks (this is the "caretaker")
15+
16+
When the "saveCurrentPage" method is called, a new bookmark (memento) is created and this one can be stored by the bookmarks manager.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Synopsis
2+
3+
In the savanna, there are predators like lions or crocodiles and there are preys like gazelles. So lions and crocodiles often attack gazelles.
4+
5+
# Problem
6+
7+
Lions and crocodiles do not attack at any moment. A lion will generally attack if a gazelle is a bit too far from the herd. A crocodile will generally attack if a gazelle is a bit too close to water, especially for drinking.
8+
9+
In programming terms, predators execute some action when a specific event occurs on the preys side. This implies the implementation of an event-handling mechanism in the code, which may be unclear if it is not properly done.
10+
11+
# Solution
12+
13+
The Observer design pattern helps a lot when we have to implement an event-driven system like this. Here this pattern is composed of:
14+
15+
* Object literals to represent different kinds of observers
16+
* An object literal to represent the observable entity
17+
18+
The observable object (gazelle) maintains a list (array) of predators. Then, depending on its actions (determined by the client code), its "notifyPredators" method may be called. This method would iterate through the array of predators and make them attack.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Synopsis
2+
3+
On any computer, I can see a power button. Generally, when the button is pressed while the computer is off, the computer is turned on. And when the button is pressed while the computer is on, the computer is turned off.
4+
5+
# Problem
6+
7+
A computer has two basic states: on and off. So when you press the power button, the system must be smart enough to understand when the computer is on and when it is off. It should also be smart enough to change its own state when the button is pressed.
8+
9+
# Solution
10+
11+
The State design pattern is obviously what we should use here. We need:
12+
13+
* An object literal to represent the context (the PC)
14+
* Object literals to represent available states (on/off)
15+
16+
Contrary to the Strategy pattern, we can access the context directly from available states (our PC is used as a parameter of the main method of both states). This allows state changes from states themselves.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Synopsis
2+
3+
I am playing a fighting game and I do not know my opponent. Should I prefer an offensive or defensive style?
4+
5+
# Problem
6+
7+
Since the opponent is unknown, the player has to choose a fighting strategy on the fly.
8+
In programming terms, we can say that an algorithm has to be selected at runtime, among several available algorithms.
9+
10+
# Solution
11+
12+
The Strategy design pattern is exactly what we need in this kind of situation. To implement this pattern, we can have:
13+
14+
* An object literal to represent the context (the fighting game)
15+
* Object literals to represent available strategies (offense and defense)
16+
17+
Offensive and defensive strategies seem to share a "fight" method, but the performed action is obviously different. Moreover, the context (fighting game) must have a reference to the current strategy because its main method ("play") is directly influenced by the selected strategy in the client code.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Synopsis
2+
3+
I am a construction professional and I always respect the basic principles of my job. I build houses and buildings following the common sense.
4+
5+
# Problem
6+
7+
Building something like a house is not trivial. It is very technical and, if you are not a construction professional, you may do things in the wrong order. For example, you could be tempted to build walls on a ground that is not fully prepared, leading to weak foundations.
8+
9+
# Solution
10+
11+
Even for professionals, it is good to have a template (like a plan drawn by an architect). This template makes it clear that you have to work on foundations first, then build walls and finally put the roof.
12+
13+
The Template design pattern is an ideal candidate to express with code this kind of situation. For this pattern, we need:
14+
15+
* Object literals to represent common constructions (house & building)
16+
* A general function that can be used as a template
17+
18+
Constructions expressed with object literals should have common methods like "foundations", "walls" or "roof" that symbolize key steps in every construction project. Then the template function can be used in the client code, passing it a construction as argument. This template function will create a house or a building by calling each method of the given construction in the right order.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Synopsis
2+
3+
I love history and I would like to visit more old monuments. But these are treasures of the past that must be protected to remain undamaged.
4+
5+
# Problem
6+
7+
If any individual can enter a historical monument and degrade it, we can say that the original structure is definitely lost. To preserve that structure, people should not be allowed to enter historical monuments without permission and supervision.
8+
9+
Applied to JavaScript, we could say this is very easy to modify directly the structure of an object and we may be tempted to do so. *But this is not what we want...
10+
11+
# Solution
12+
13+
The Visitor design pattern is a way to preserve an object structure. Operations on this object structure are still possible but they are kept separate to some extent, so they do not modify its essence.
14+
15+
To implement the Visitor design pattern, we can have:
16+
17+
* A factory function to create monuments
18+
* An object literal to represent a tourist (visitor)
19+
20+
Each monument has an "accept" method which takes a visitor object as parameter. The role of this method is to call the "visit" method of the visitor with a reference to the monument on which the "accept" method was called (using "this").
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Synopsis
2+
3+
I am a sysadmin and I work for a company where each employee can choose its operating system. So I often need to install and run various operating systems based on GNU/Linux, Mac OS or Windows.
4+
5+
# Problem
6+
7+
There are several families of operating systems and there are many operating systems in each family.
8+
If we try to handle all the instantiation logic in the client code, it will most likely be a mess.
9+
10+
As a system administrator, you only want to know how to get an instance of a specific OS in a given family. You do not need to know how Debian, Mac OS X or Windows XP have been programmed to make them available on some computers.
11+
12+
# Solution
13+
14+
AbstractFactory is a great solution here. We could consider it as a superset of the Factory pattern, but there is significantly more work to do. Indeed, we need a factory function for each OS family and of course a factory of factories that will be the entry point of the associated module.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Synopsis
2+
3+
I have to buy a new PC, but not a standardized one. On the manufacturer's website, I chose every single component before validating my order. Now I am looking forward to using this new computer!
4+
5+
# Problem
6+
7+
A PC contains a lot of components that are dynamically assembled by a third-party workforce which is employed by a manufacturer. Due to the flexibility of JavaScript, it would be possible to have only one object (the PC) and manipulate its properties directly. But this is not ideal if we want to keep the basic structure of the problem that comes from a real-life situation.
8+
9+
# Solution
10+
11+
The Builder pattern allows us to build our PC step by step with only three objects (literals):
12+
13+
* The PC
14+
* The workforce (e.g. a geek)
15+
* The manufacturer
16+
17+
When the manufacturer will receive an order, it will ask its workforce to build the custom PC step by step through its "manufacture" method.
18+
19+
N.B. Since we do not use constructor functions in the idiomatic style, this version of the Builder pattern is not a solution to the telescoping constructor problem. But you might be interested in the "Object Specifier" pattern...
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Synopsis
2+
3+
I am a fan of GNU/Linux distributions and I want to test the big names: Debian, RedHat, Slackware.
4+
5+
# Problem
6+
7+
Debian, RedHat and Slackware are all Linux distributions.
8+
We could create directly an object literal to represent each one, but this is not necessarily the best choice.
9+
We are not sure to use each instance in our code and we do not want to use memory for nothing.
10+
For the sake of clarity and performance, it may be nice to delegate the instantiation logic.
11+
12+
# Solution
13+
14+
Factory makes it possible to do so. To implement this design pattern, we only need to create a function that will return objects.
15+
16+
In JavaScript, a function or method that returns objects is generally considered as a factory. It is a well-known idiomatic alternative to the use of the "new" keyword along with constructor functions.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Synopsis
2+
3+
When I order something, I sometimes like to have a paper invoice.
4+
But when the order is important, I do not want to lose the document.
5+
Therefore, I want to be able to make photocopies.
6+
7+
# Problem
8+
9+
Creating a new object with "new" is not the same thing as cloning an existing object.
10+
The good point about JavaScript is that the language is prototype-based.
11+
The built-in Object.create() method already performs some kind of cloning.
12+
However, we cannot clone properly if we only use Object.create().
13+
The parameter of this method (the original object) is used as the prototype of the new object.
14+
This means the new object will not have own properties like the original object.
15+
These properties would be available in the new object, but in its prototype.
16+
17+
# Solution
18+
19+
We need only two things in this situation:
20+
21+
* An object (literal) that we want to clone (e.g. invoice)
22+
* A custom cloning function that will take the object to clone as a parameter
23+
24+
N.B. Most of the time, it is not even useful to have an exact copy of an object in JavaScript. The important thing is often to be able to use the same properties on several objects, and for that purpose, a simple Object.create() is generally good enough.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Synopsis
2+
3+
As a person, I am unique. No one has exactly my DNA.
4+
5+
# Problem
6+
7+
In JavaScript, we can create several instances of everything using:
8+
9+
* An object literal: e.g. {}
10+
* The static method "create" of "Object": e.g. Object.create(Object.prototype)
11+
* The "new" operator on a constructor function: e.g. new Object()
12+
13+
Therefore, I cannot be sure that there will not be other instances of myself in the code!
14+
15+
# Solution
16+
17+
Singleton is the key!
18+
19+
But due to the nature of JavaScript, an object literal is already a sort of Singleton. Each object literal is unique and is built from the prototype of Object. In a way, we could see an object literal as a an anonymous class whose instance is delivered immediately. However, we could also argue that an object literal is nothing more than an instance of Object, which is actually true. With this in mind, it is quite obvious that an object literal is not a pure Singleton, but if flexibility matters, it is quite reasonable to consider it as a Singleton.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Synopsis
2+
3+
I have some amazing photos on my computer that I would like to display using my old projector. But my PC uses HDMI and my projector uses VGA.
4+
5+
# Problem
6+
7+
HDMI and VGA are not compatible interfaces. HDMI can handle images and sound through a digital signal whereas VGA can only handle images through an analog signal.
8+
9+
# Solution
10+
11+
Adapter is a well-known solution in this kind of situation. Here we need very few things:
12+
13+
* An object (literal) that represents the VGA connection
14+
* An object (literal) that represents the HDMI to VGA adapter
15+
16+
The latter must have a reference to the first one and must be the entry point of the module. Then the main method of the adapter will delegate some work to the main method of the VGA connection.

0 commit comments

Comments
 (0)