Many objects in OOP are not data abstractions, but rather are used as a way to save configurations to perform repetitive actions, such as generating HTML from Markdown, or determining a city by IP. Configuration is done by passing options to the object constructor, and the options themselves are stored internally and used for all subsequent calls.
// timeout sets a limit of one second for the duration of the query
const ipgeo = new IpGeo({ timeout: 1000 });
ipgeo.resolve('123.4.3.2');
But what if, for a particular query, you need to temporarily set options that are different from those passed to the constructor? There are three possible solutions to this situation.
Create a new object
The simplest solution is to create a new object where we want it. This solution, although simple, has a number of disadvantages. The main drawback is related to the fact that it's impossible to substitute the implementation (the same polymorphism that we'll talk about in the future), because the object isn't created at the system configuration stage, but rather at the place where the call takes place. This, in turn, leads to duplication of common options, and testing becomes difficult (if not impossible).
const ipgeo = new IpGeo({ timeout: 10 });
ipgeo.resolve('123.4.3.2');
Setters
The worst option involves the use of setters.
const ipgeo = new IpGeo({ timeout: 1000 });
// In one part of the program
ipgeo.resolve('123.4.3.2');
// In the other part of the program
ipgeo.setOption('timeout', 10);
ipgeo.resolve('123.4.3.2');
Variable state, the hardest thing in programming. The variable state is the root cause of almost all the problems we encounter and creates bugs that are dangerous and hard to catch. Guess what will go wrong after the last two lines? Our ipgeo
object is shared by all parts of the system, which means that changing it in one place will affect all subsequent calls. In the case of Markdown, it gets more dangerous, because incorrect output creates security holes, specifically it makes it possible to perform XSS attacks:
const md = new Markdown({ sanitize: true });
// In one part of the program
md.render(markdown);
// Disable sanitize in the other part of the program
md.setOption('sanitize', false);
md.render(markdown2);
sanitize
is the flag responsible for enabling safe rendering. If you turn it off, the <script>
tags inserted in Markdown will be displayed as is. This is sometimes necessary and acceptable for your own text (for example,for lessons' texts of Hexlet), but unacceptable for text entered by users. Changing the md
object creates a security hole. You can avoid it by remembering to put the option back:
const md = new Markdown({ sanitize: true });
// In one part of the program
md.render(markdown);
// Disable sanitize in the other part of the program
md.setOption('sanitize', false);
md.render(markdown2);
md.setOption('sanitize', true);
Programmers are bound to forget to do this, human error is always at play. This kind of code, in which something first changes one way and is then restored to a previous version, almost always indicates an architecture problem and can be rewritten in a safer form.
New options at query time
The appropriate approach solves all the problems mentioned above. It is based on passing an additional parameter to the method. This parameter contains temporary options that apply only to this query.
const md = new Markdown({ sanitize: true });
// In one part of the program
md.render(markdown);
// Turn off sanitize for the duration of the query in the other part of the program
md.render(markdown2, { sanitize: false });
md.render(markdown3); // sanitize is still true
Now everything is OK. Sanitize is enabled globally, but in one particular query, it was overridden by md.render(markdown, { sanitize: false })
This has no effect on subsequent calls of the render()
method.
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.