JavaScript composer

Translation of the article was prepared on the eve of the start of the course JavaScript Developer. Basic “


In this article, we will break down one of the structural design patterns in JavaScript – linker… In software engineering, the linker allows you to refer to groups of objects as if they were separate objects, which ensures that the overall structure of these objects and their combinations is consistent.

The main task of the linker is Union many objects into a single tree structure… This tree structure represents a hierarchy based on the principle from particular to the whole

To better understand how the linker works, you need to understand how the hierarchy from particular to whole works and how it can be visualized.

In the hierarchy from private to integer, each object of the collection iscommon compositions. This general composition, in turn, is a collection of its partsHierarchy from the particular to the whole is built as a tree structure, where each separate “Leaf” or “node” is perceived and processed the same waylike any other leaf or node in any part of the tree. So a group or collection of objects (a subtree of sheets / nodes) is also a leaf or a node.

Visually, it can be represented something like this:

Now that we have a clearer understanding of the relationship between the private and the whole, let’s return to the term linker… We have determined that the use of the linker is intended to unite the mentioned objects (leaves / nodes) into a tree according to this principle.

Thus, we get a design pattern in which each element of the collection can also include others collection, which allows you to build deeply nested structures.

Internal structure

Every node in the tree shares a common set of properties and methodsallowing it to maintain and interact with individual objects in the same way as with collections of objects. This interface assumes the construction of recursive algorithms that iterate over all objects in the composite collection.

Where does this pattern apply?

On operating systems, this pattern allows many possibilities, such as creating directories within directories.

Files (for convenience, all objects in the directory can be read “Elements”) are leaves / nodes (parts) inside the whole composite (directory). A subdirectory created in a directory is similarly a leaf or a node that includes other elements such as videos, images, etc. At the same time, both directories and subdirectories are also compositesbecause they are collections of separate parts (objects, files, etc.).

Popular libraries like React or Vue use this pattern extensively to build reliable, reusable interfaces. All elements of the web pages that you see are presented as components… Each component of a web page is a leaf of a tree, and it itself can combine many components (in this case, composite, but he still remains a leaf of wood). It is a powerful tool that greatly simplifies development for library users. In addition, it allows you to create scalable applications that involve multiple objects.

Why is this template interesting?

In short: It is very powerful.

The linker is such a powerful design pattern because it allows an object to be treated as a composite by using a common interface for all objects.

This means you can reuse objects without fear of potential incompatibility with others.

When developing an application, you may need to work with objects that have a tree structure, in which case using this pattern can be very effective.

Examples of

Let’s say we are developing an app for a company that helps doctors get certified for platforms that provide healthcare services remotely. The process includes collecting signatures for statutory documents.

We have to work with the class Documentwhich will have the property signature with a default value of false. If the doctor signs the document, the signature value will be changed to his signature. We also define in this class the method sign, with which this function is implemented.

This is how it will look Document:

class Document {
  constructor(title) {
    this.title = title
    this.signature = null
  }
  sign(signature) {
    this.signature = signature
  }
}

Now, with the use of a linker, we will provide support for methods similar to those defined in Document

class DocumentComposite {
  constructor(title) {
    this.items = []
    if (title) {
      this.items.push(new Document(title))
    }
  }

  add(item) {
    this.items.push(item)
  }

  sign(signature) {
    this.items.forEach((doc) => {
      doc.sign(signature)
    })
  }
}

Now the grace of the template becomes apparent. Notice the last two code snippets: Let’s take a look at the template visually:

Fine! It looks like we are on the right track. What we got corresponds to the scheme presented above.

So, our tree structure contains two leaves / nodes – Document and DocumentComposite… They both share the same interface and hence act like “Parts” a single composite wood

It should be noted here that the leaf / node of the tree, not being composite (Document), is not a collection or group of objects and therefore will not branch out further. Still leaf / node, being composite, contains a collection of parts (in our case, this items). Also remember that Document and DocumentComposite share a common interface, and therefore share the sign method.

So what is the effectiveness of this approach? Although DocumentComposite uses a single interface because it uses a sign method like Document, it takes a more efficient approach while still achieving its ultimate goal.

So instead of a structure like this:

const pr2Form = new Document(
  'Primary Treating Physicians Progress Report (PR2)',
)
const w2Form = new Document('Бланк Налогового управления (W2)')

const forms = []
forms.push(pr2Form)
forms.push(w2Form)

forms.forEach((form) => {
  form.sign('Bobby Lopez')
})

We can modify the code and make it more efficient by taking advantage of the linker:

const forms = new DocumentComposite()
const pr2Form = new Document(
  'Текущие сведения о производственных врачах (PR2)',
)
const w2Form = new Document('Бланк Налогового управления (W2)')
forms.add(pr2Form)
forms.add(w2Form)

forms.sign('Роман Липин')

console.log(forms)

With this approach, we only need to execute sign once after adding all the necessary documents, and this function will sign all documents.

You can verify this by looking at the output of the function console.log(forms):

In the previous example, we had to manually add documents to an array, and then independently iterate over each document and execute the function signto sign it.

Also, do not forget that our DocumentComposite can include a collection of documents.

So when we did this:

forms.add(pr2Form) // Документ
forms.add(w2Form) // Документ

Our scheme took the following form:

We have added two forms, and now this scheme is almost completely identical to the original one:

Nevertheless, our tree stops growing, since its last leaf has formed only two leaves, which does not quite correspond to the diagram in the last screenshot. If instead we made the w2form a composite, as shown here:

const forms = new DocumentComposite()
const pr2Form = new Document(
  'Текущие сведения о производственных врачах (PR2)',
)
const w2Form = new DocumentComposite('Бланк Налогового управления (W2)')
forms.add(pr2Form)
forms.add(w2Form)

forms.sign('Роман Липин')

console.log(forms)

Then our tree could continue to grow:

Ultimately, we would have achieved the same goal – all documents would have been signed:

This is where the linker comes in.

Conclusion

That’s all for now! I hope this information was helpful to you. Further more!

Find me on medium

Read more:

  • Questions I was asked in front-end interviews

Similar Posts

Leave a Reply