Reader small image

You're reading from  JavaScript Design Patterns

Product typeBook
Published inMar 2024
Reading LevelIntermediate
PublisherPackt
ISBN-139781804612279
Edition1st Edition
Languages
Right arrow
Author (1)
Hugo Di Francesco
Hugo Di Francesco
author image
Hugo Di Francesco

Hugo Di Francesco is a software engineer who has worked extensively with JavaScript. He holds a MEng degree in mathematical computation from University College London (UCL). He has used JavaScript across the stack to create scalable and performant platforms at companies such as Canon and Elsevier and in industries such as print on demand and mindfulness. He is currently tackling problems in the travel industry at Eurostar with Node.js, TypeScript, React, and Kubernetes while running the eponymous Code with Hugo website. Outside of work, he is an international fencer, in the pursuit of which he trains and competes across the globe.
Read more about Hugo Di Francesco

Right arrow

Implementing Structural Design Patterns

Structural design patterns give us tools to handle connecting different objects; in other words, managing the relationships between objects. This includes techniques to reduce memory usage and develop functionality with existing classes without modifying these existing classes. In addition, JavaScript features allow us to more effectively apply these patterns. Modern JavaScript includes some built-ins that allow us to implement structural design patterns in a more efficient manner.

We’ll cover the following topics in this chapter:

  • Defining structural design patterns as a whole, and proxy, decorator, flyweight, and adapter specifically
  • An implementation of the proxy pattern with a class-based approach as well as an alternative using Proxy and Reflect
  • Multiple implementations of the decorator pattern, leveraging JavaScript first-class support for functions
  • An iterative approach to implementing flyweight in JavaScript...

Technical requirements

You can find the code files for this chapter on GitHub at https://github.com/PacktPublishing/Javascript-Design-Patterns

What are structural design patterns?

When building software, we want to be able to connect different pieces of code (e.g., classes and functions) and change how the parties involved in these connections and relationships interact without having to jump through multiple fragmented parts of the codebase.

Structural design patterns allow us to add, remove, and change functionality in modules and classes safely. The “structural” aspect of these patterns is due to the fact that we can play around with implementations if the exposed interfaces are stable.

Structural design patterns are a good way to maintain the separation of concerns and loose coupling of different classes and modules while maintaining a high development velocity.

In the next section, we’ll look at multiple approaches to implement the Proxy pattern in JavaScript.

Implementing the Proxy pattern with Proxy and Reflect

The proxy pattern involves providing an object (the subject, or real object) that fulfills a certain interface. The proxy (a placeholder or wrapper object) controls access to the subject. This allows us to provide additional functionality on top of the subject without changing a consumer’s interactions with the subject.

This means that a proxy needs to provide an interface matching the subject.

By using the proxy pattern, we can intercept all operations on the original object and either pass them through or change their implementation. This follows the open/closed principle, where both the subject and consumer are closed for modification, but the proxy provides us with a hook to extend, which means the design is open to extension.

A redaction proxy implementation

We’ll start with the following implementation class that has a couple of methods that output strings:

class Implementation {
  someFn...

Decorator in JavaScript

The decorator pattern is similar to the proxy pattern in that it’s about “wrapping” an object. However, the decorator pattern is about adding functionality to an object at runtime. Different decorators can be applied to an object to add different functionalities to it.

Implementation

Given the following HttpClient class based on the fetch API, we want to instrument the requests made through this client. HttpClient implements getJson and returns JSON output if the fetch request succeeds:

class HttpClient {
  async getJson(url) {
    const response = await fetch(url);
    if (response.ok) {
      return response.json();
    }
    throw new Error(`Error loading ${url}`);
  }
}

InstrumentedHttpClient, which is a decorator, might look like the following, where we expose the same getJson method but have the...

Flyweight in JavaScript

The flyweight pattern is where the subset of object properties that have the same value are stored in shared “flyweight” objects.

The flyweight pattern is useful when generating large quantities of objects that share a subset of the same values.

Implementation

One concept from domain-driven design by Eric Evans is “value objects”. These value objects have the property that their contents matter more than their identity. Let’s take the example of a value object being a “coin” where, for the purposes of payment, two 50-cent coins are interchangeable.

Value objects are interchangeable and immutable (a 50-cent coin can’t become a 10-cent coin). These types of objects are therefore a great fit for the Flyweight pattern.

Not all properties of a “coin” are “value”-driven, for example, certain coins are made from certain materials and coins tend to be issued in a certain...

Adapter in JavaScript

The adapter pattern, similar to the other structural design patterns, focuses on interfaces.

In the adapter pattern’s case, it involves being able to use a new implementation without changing the consumer or the implementation’s interface. The “adapter” takes the new implementation and “adapts” the interface to match what the consumer expects.

We’re not changing the implementation or the consumer; rather, we’re building an adapter to wrap the implementation and plug it into the consumer without changing either.

Implementation

Let’s start with a simple in-memory database that uses a naive IdGenerator to generate keys for the database entries by encoding the object as a string.

Database has a createEntry method that stores given data using the IdGenerator to generate a key. Database also has a get method to recall entries by ID:

class IdGenerator {
  get(entry) {
  ...

Summary

In this chapter, we’ve looked at how structural design patterns enable the extension of functionality without needing to rework interfaces in JavaScript.

The proxy design pattern is useful when we want to intercept calls to an object without changing the interface.

By contrast, the decorator design pattern concerns itself with dynamically adding functionality through new instance members.

The flyweight pattern can be used effectively for managing large numbers of objects, which is especially useful for value objects. There are workarounds in JavaScript for some of the ergonomic drawbacks of it.

The adapter pattern allows us to integrate multiple classes, modules, or functions with different opinions and interfaces without modifying them. The shape of the adapter is dictated by the existing modules and classes that we’re attempting to connect together.

Now that we know how to organize relationships between different objects and classes with structural...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
JavaScript Design Patterns
Published in: Mar 2024Publisher: PacktISBN-13: 9781804612279
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Hugo Di Francesco

Hugo Di Francesco is a software engineer who has worked extensively with JavaScript. He holds a MEng degree in mathematical computation from University College London (UCL). He has used JavaScript across the stack to create scalable and performant platforms at companies such as Canon and Elsevier and in industries such as print on demand and mindfulness. He is currently tackling problems in the travel industry at Eurostar with Node.js, TypeScript, React, and Kubernetes while running the eponymous Code with Hugo website. Outside of work, he is an international fencer, in the pursuit of which he trains and competes across the globe.
Read more about Hugo Di Francesco