DEV Community

Meysam Faghfouri
Meysam Faghfouri

Posted on

Decorator pattern in javascript

One of the interesting patterns in the programming world is the decorator pattern.
this is a definition which I've taken from Wikipedia.
"In object-oriented programming, the decorator pattern is a design pattern that allows the behaviour to be added to an individual object, dynamically, without affecting the behaviour of other objects from the same class."
we can use that to add some extra behaviour in our methods for example logging, measuring running time, prevent special input to send to the functions and etc.
I myself used this pattern several times in my own back-end projects with C# but I was excited to create a simple library to do this in javascript so I decided to share my experience with you.
First of all, I've created a repository for this library and you can access the code via this link:
https://github.com/mfaghfoory/javascript-object-decorator

there is a simple function called 'decorate' inside js-decorator.js file and it takes 5 parameters (four of them are optional) and returns a decorated object.

decorate(object, [beforeCall], [afterCall], [onCall], [onException])

For example, imagine we have an object like this:

let product = {
  name: "tv",
  price: 600,
  printInfo() {
    console.log(`${this.name}-${this.price}$`);
  },
  logToDb() {
    //send this object to DB
  }
};

and we want to log some functions result or measure its running time so we can create our hook functions like this and pass them to 'decorate' function:

let beforeCall = res => {
};
let afterCall = res => {
};
let onCall = res => {
};
let onException = error => {
};
product = decorate(product, beforeCall, afterCall, onCall, onException);

For example:

let beforeCall = res => {
  console.log("before call:" + JSON.stringify(res));
  console.time();
};
let afterCall = res => {
  console.log("after call:" + JSON.stringify(res));
  console.timeEnd();
};
let onCall = (func, args) => {
  //can modify the result like this:
  //let res = func(args);
  //return '--' + res + '--'
};
let onException = error => {
  //log error to db
};
product = decorate(product, beforeCall, afterCall, onCall, onException);
product.printInfo();

//Result:

//before call:{"method":"printInfo","args":[],"object":{"name":"tv","price":600}}
//tv-600$
//after call:{"method":"printInfo","args":[], result: undefined,"object":{"name":"tv","price":600}}
//default: 0.291015625ms

I've just created this library so feel free to give your suggestions and I'll be happy to apply your good ideas in the repository.

Happy coding :)

Top comments (0)