JS and Design Patterns - Chapter 3 🚀
Tags: javascript, webdev, programming, codequality
Published: 2021-01-22 21:54:30

Table Of Contents
        * 🤓[INTRODUCTION](#intro)
        * 👤[USER DECORATOR](#user)
        * ☕[COFFEE SHOP DECORATOR](#coffee-shop)
        * ❓ [WHY AND WHEN DO WE USE DECORATOR PATTERN?](#why-use)
        * 🔵[DIFFERENT TYPES OF DECORATOR PATTERN](#diff-types)
        * 📚[REACT EXAMPLE](#react-example)
        * 🙏[THANK YOU](#thank-you)


## INTRODUCTION <a name="intro"></a>

Welcome my fellow coders! I hope you are having a great time. Today was a very productive day, let's finish this week strong and talk about another interesting Design Pattern, a guy responsible for dynamically adding behavior to the existing classes - 🎉**THE DECORATOR PATTERN**

![Decorator](https://media.giphy.com/media/xUySTJhx2jKGQX2L2E/giphy.gif)

The decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically. Let me explain it by using examples.

## JAVASCRIPT CODE IMPLEMENTATION

#### USER DECORATOR <a name="user"></a>
```javascript
var User = function(name) {
    this.name = name;
 
    this.say = function() {
        log.add("User: " + this.name);
    };
}
 
var DecoratedUser = function(user, street, city) {
    this.user = user;
    this.name = user.name;  // ensures interface stays the same
    this.street = street;
    this.city = city;
 
    this.say = function() {
        log.add("Decorated User: " + this.name + ", " +
                   this.street + ", " + this.city);
    };
}
 
// logging helper
 
var log = (function() {
    var log = "";
 
    return {
        add: function(msg) { log += msg + "\n"; },
        show: function() { alert(log); log = ""; }
    }
})();

var user = new User("Kelly");
user.say();
 
var decorated = new DecoratedUser(user, "Broadway", "New York");
decorated.say();
 	
log.show();

```

### COFFEE SHOP DECORATOR STORY <a name="coffee-shop"></a>
Now imagine a coffee shop. The coffee shop only sells coffee. But, the clever manager figured out that they could earn an extra 💰 by selling different coffee condiments separately. We can help them manage that. Let's see how we can use our Decorator Pattern in this case.

❗ NOTE: PLEASE READ THE COMMENTS 👩‍💻

```javascript
//Constructor that will be decorated
function Coffee(desc) { 
    //the type of the copy
    this.type = desc;
    //the description that will be modified
    this.description = desc;
    /*
       A function expression is very similar to
       and has almost the same syntax as a function
       declaration. The main difference between a function
       expression and a function declaration
       is the function name,  which can be omitted
       in function expressions to create anonymous functions
       A function expression can be used as an Immediately
       Invoked Function Expression
    */
    this.cost = function () { return 1.99; }; 
    this.desc = function () { return this.description; }; 
    //A regular function
    function type () { return this.type } ;
} 

//We are going to "decorate" our coffee with whip, Milk,
//Soy or whatever you want, you just need to add another
//condiment function
//which is going to change the price and the description that 
//we see at the end
//Decorator 1
function Whip(houseBlend){
    var hbCost = houseBlend.cost();
    var hbDesc = houseBlend.desc();
    houseBlend.desc = function(){
        return hbDesc + ", Whip";
    };
    houseBlend.cost = function(){
        return hbCost + .09;
    };
}
//Decorator 2
function Milk(houseBlend){
    var hbCost = houseBlend.cost();
    var hbDesc = houseBlend.desc();
    houseBlend.desc = function(){
        return hbDesc + ", Milk";
    };
    houseBlend.cost = function(){
        return hbCost + .1;
    };
}
//Decorator 3
function Soy(houseBlend){
    var hbCost = houseBlend.cost();
    var hbDesc = houseBlend.desc();
    houseBlend.desc = function(){
        return hbDesc + ", Soy";
    };
    houseBlend.cost = function(){
        return hbCost + .12;
    };
};
//We create a brand new coffee object instance
//for example Espresso (type="Espresso", description="Espresso")
let coffee = new Coffee("Espresso");
//Double milk decorator
Milk(coffee);
Milk(coffee);
//A whip
Whip(coffee);
//And a soy? 😲
//(This ain't coffee anymore, I don't know what this is...😂)
Soy(coffee);
//fancy console log
console.log('%c%s', 'color: black; background: red; font-size: 24px;', "Coffee: " +coffee.desc()+` ${coffee.cost()}`);
let coffee2 = new Coffee("House Blend");
Milk(coffee2);
//A whip
Whip(coffee2);
console.log('%c%s', 'color: black; background: red; font-size: 24px;', "Coffee: " +coffee2.desc()+`, $${  coffee2.cost()}`);

//Output
//Coffee: Espresso, Milk, Milk, Whip, Soy, $2.4
```
In the previous coffee shop example, we saw that it is possible to apply multiple decorators, which can come in handy sometimes.

## ❓ WHY AND WHEN DO WE USE DECORATOR PATTERN?<a name="why-use"></a>
Decorators use a special syntax in JavaScript, whereby they are prefixed with an @ symbol and placed immediately before the code being decorated. (see [tc39](https://tc39.es/proposal-decorators/))

It's possible to use as many decorators on the same piece of code as you desire, and they'll be applied in the order that you declare them. Example:
```typescript
@log()
@immutable()
class Example {
  @time('demo')
  doSomething() {
    //
  }
}
```
This is going to define a class and apply decorators - two to the class itself, and one to a property of a the class
- @\log - could log all access to the class
- @immutable - could make the class immutable - by calling [Object.freeze()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)
- time - will record how long a method takes to execute and log this out with a unique tag.

Decorators can allow for a cleaner syntax for applying this kind of wrapper around your code. Whilst function composition is already possible, it is significantly more difficult - or even impossible - to apply the same techniques to other pieces of code.

## 🔵 DIFFERENT TYPES OF DECORATOR PATTERN<a name="diff-types"></a>

- Class member decorators
  Property decorators are applied to a single member in a class — 
  whether they are properties, methods, getters, or setters. This 
  decorator function is called with three parameters:

  - **target** - the class that the member is on.
  - **name** - the name of the member in the class.
  - **descriptor** - the member descriptor. This is essentially 
  the object that would have been passed to 
  [Object.defineProperty](https://developer.mozilla.org/en- US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).

The classic example used here is @readonly.
```javascript
function readonly(target, name, descriptor) {
  descriptor.writable = false;
  return descriptor;
}
```

- Class decorators
  Class decorators are applied to the entire class definition all 
  in one go. The decorator function is called with a single 
  parameter which is the constructor function being decorated.
  In general, these are less useful than class member decorators, 
  because everything you can do here you can do with a simple 
  function call in exactly the same way. Anything you do with 
  these needs to end up returning a new constructor function to 
  replace the class constructor.

## 📚 REACT EXAMPLE<a name="react-example"></a>
React makes a very good example because of the concept of Higher-Order Components. These are simply React components that are written as a function, and that wrap around another component. These are ideal candidates for use as a decorator because there's very little you need to change to do so. For example. the react-redux library has a function, connect. That's used to connect a React component to a Redux store.

In general, this would be used as follows:
```javascript
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
```
However, because of how the decorator syntax works, this can be replaced with the following code to achieve the exact same functionality:

```javascript
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
```
Decorators, especially class member decorators provide a very good way of wrapping code inside a class in a very similar way to how you can already do so for freestanding functions.

Some real-world examples: 
- [Core decorators](https://www.npmjs.com/package/core-decorators)
- [React](https://reactjs.org/)
- [MobX](https://mobx.js.org/README.html)

# 🙏 THANK YOU FOR READING!<a name="thank-you"></a>
Please leave the comment, tell me about you, about your work, comment your thoughts, connect with me via  [Twitter](https://twitter.com/lazar_dev) or  [LinkedIn](https://www.linkedin.com/in/lazar-stankovic-44a199177/). 

Let this year be your year, let this year be our year. Until the next typing...

Have a nice time!

References:
School notes...
[tc39](https://tc39.es/proposal-decorators/)
[sitepoint](https://www.sitepoint.com/javascript-decorators-what-they-are/)

☕ SUPPORT ME AND KEEP ME FOCUSED!
<a href='https://ko-fi.com/Z8Z33D1HJ' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi4.png?v=2' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
 😊